
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>
#include <errno.h>
#include <wchar.h>
#include <assert.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>

#include <unistd.h>
#include <linux/input.h>
#include <linux/fb.h>
#include <linux/types.h>

#include <string>
#include <fstream>
#include <map>
#include <list>
#include <vector>
#include <typeinfo>
#include <stack>
#include <algorithm>

#include <png.h>
#include <jpeglib.h>
#include <jerror.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

#include "parse.h"

#define BLACK     RGB(0,0,0)         /*黑色*/
#define WHITE     RGB(255,255,255)   /*白色*/
#define RED       RGB(255,0,0)       /*红色*/
#define GREEN     RGB(0,255,0)       /*绿色*/
#define BLUE      RGB(0,0,255)       /*蓝色*/
#define LIGHTGRAY RGB(180,180,180)   /*浅灰色*/
#define DARKGRAY  RGB(128,128,128)   /*深灰色*/
#define YELLOW    RGB(255,255,0)     /*黄色*/
#define DARKGREEN RGB(0,128,0)       /*深绿色*/
#define LIGHTBLUE RGB(0,128,255)     /*浅蓝色*/
#define CYAN      RGB(0,255,255)     /*青色*/
#define PINK      RGB(255,128,192)   /*粉红色*/
#define ORANGE    RGB(255,128,0)     /*橙色*/
#define MAGENTA   RGB(255,0,255)     /*紫色*/
#define BROWN     RGB(128,0,64)      /*褐色*/

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
#define MIN(a, b) ( (a) < (b) ? (a) : (b) )

typedef unsigned char Byte;
typedef unsigned int Rgb;

#define kDefualtWmConfigFile "./wm.cfg"

#define kConfWallpapper "wallpaper"
#define kConfFramebuffer "framebuffer"
#define kConfMouse "mouse"
#define kConfKeyBoard "keyboard"

#define kConfAppWinBtnCloseEnter "btnCloseEnter"
#define kConfAppWinBtnCloseLeave "btnCloseLeave"
#define kConfAppWinBtnCloseFocusOut "btnCloseFocusOut"

#define kConfAppWinBtnMinLeave "btnMinLeave"
#define kConfAppWinBtnMinEnter "btnMinEnter"
#define kConfAppWinBtnMinFocusOut "btnMinFocusOut"

#define kConfAppWinBtnMaxLeave "btnMaxLeave"
#define kConfAppWinBtnMaxEnter "btnMaxEnter"
#define kConfAppWinBtnMaxFocusOut "btnMaxFocusOut"

#define kConfMouseCursor "mouseCursor"
#define kConfDefaultFont "defaultFont"

#define TrackLog() printf("%s %d\n", __FUNCTION__, __LINE__);

typedef enum {
    kWmMouseEvent = 0,
    kWmKeyEvent
}WmEventType;

typedef enum {
    kWmLeftButtonClick = 1,
    kWmLeftButtonUp,
    kWmLeftButtonDClick,
    kWmLeftButtonDown,
    kWmRightButtonDown,
    kWmMouseEnter,
    kWmMouseLeave,
    kWmMouseMove,
    kWmMouseDragMove,
    kWmKeyUp,
    kWmKeyDown,
    kWmKeyKeep
}EventType;

typedef enum {
    kApplicationWindow = 0,
    kDesktopWindow,
    kPanelWindow,
    kPanelItemWindow,
    kStartMenu,
    kAppIconWindow
}WindowType;

typedef enum {
    kCloseButton = 0,
    kMinButton,
    kMaxButton
}ButtonLayerType;

typedef enum {
    kWinAlwayOnTop = 0,
    kWinNormal,
    kWinAlwayOnBottom,
    kWinPanelItem
}WinPositionType;

const static int kAppWindowBorder = 8;

struct Event {
    WmEventType where;
    EventType type;
    int dx, dy;
    int x, y;
    char code;
    bool next_handler;
};

class NonCopyable {
protected:
    NonCopyable() {}
    virtual ~NonCopyable() {}

private:
    NonCopyable(const NonCopyable &);
    const NonCopyable& operator= (const NonCopyable &);
};

struct Point {
    Point();
    Point(int x, int y);

    int x, y;
};

struct Rect {
    static bool IntersetRect(Rect &dst, const Rect &src1, const Rect &src2);
    bool PointInRect(int x, int y);
    Rect();
    Rect(int left, int top, int right, int bottom);
    int GetWidth() const;
    int GetHeight() const;
    int GetX() const;
    void Inflate(int dx, int dy);
    int GetY() const;
    void print() const;

    int left, top, right, bottom;
};

void Rect::print() const
{
    printf("%d %d %d %d\n", left, top, right, bottom);
}

struct Color {
    static inline Color FromRGB(Rgb rgb);

    Color();
    Color(Byte r, Byte g, Byte b) ;
    Rgb ToRGB();

    //alpha : 255(not transparent), 0(transparent)
    Byte b,g,r, alpha;
};

struct Pixel {
    Byte b,g,r;
};


class Bitmap : NonCopyable{
public:
    Bitmap(int width, int height);
    ~Bitmap();

    inline Color* GetBuffer();
    inline Color& GetPixel(int x, int y);
    inline void SetPixel(int x, int y, Color& src);
    inline void SetAlphaPixel(int x, int y, Color &src, float alpha);

    //bitmap alpha
    bool BiltAlpha(int x1, int y1, Bitmap *src, int x0, int y0, 
                   int w, int h, int alpha);

    //no alpha
    bool Bilt(int x1, int y1, Bitmap *src, int x0, int y0, int w, int h);

    //font 
    bool BiltFont(int x1, int y1, Bitmap *src, 
                  int x0, int y0, int w, int h);

    //no alpha, mask color will not bilt
    bool BiltMaskColor(int x1, int y1, Bitmap *src, 
                       int x0, int y0, int w, int h, Rgb mask);

    bool BiltPng(int x1, int y1, Bitmap *src, int x0, int y0, 
                 int w, int h);

    void FillColor(Rgb rgb);
    bool DrawRect(Rect &rect, Color color);
    bool DrawLine(Point &p1, Point &p2, Color color);

    void AdjusctBrightContrast(int bright, int contrast, Byte threshold);

private:
    bool BiltLimit(int &x1, int &y1, int &x0, int &y0, int &w, int &h);
    inline int CheckValue(int value);

public:
    int width, height;
private:
    Byte alpha;
    Color *data;
};

class ImageUtils {
private:
    typedef Bitmap* (*LoadImageFun)(const char*);

public:
    static Bitmap* LoadImage(const char *file_path);
    static Bitmap* LoadImage(const char *file_path, int dst_width, int dst_height);
    static Bitmap* ResizeImage(Bitmap *src, int dst_width, int dst_height);

private:
    static Bitmap* LoadPNG(const char *file_name);
    static Bitmap* LoadBMP(const char *file_name);
    static Bitmap* LoadJPG(const char *file_name);
};



class Font : NonCopyable{
public:
    Font(int w, int h, int left, int top);
    ~Font();
    Byte* GetBuffer();
    void Render(Bitmap *bitmap, Rgb rgb);

public:
    int width,height;
    int left, top;
private:
    Byte *data;

};


class FontManager : NonCopyable{
public:
    static FontManager& GetInstance();
    static wchar_t* UTF8ToUnicode( const char *src);

    void Release();
    Bitmap* DrawText(const char *text, int font_size, Rgb rgb);

private:
    FontManager();
    static wchar_t CovertCode(Byte *in);
    Font* FtBitmapToFont(FT_Bitmap* bitmap, int left, int top);

private:
    FT_Library library;
    FT_Face  face;
    static FontManager* instance;
};


class FrameBuffer : NonCopyable{
public:
    static FrameBuffer& GetInstance();
    void Release();

    bool BiltScreen(Bitmap *bitmap);

    bool BiltCursor(int x1, int y1, Bitmap *src, int x0, int y0, 
                    int w, int h);

    bool Bilt(int x1, int y1, Bitmap *src, int x0, int y0, int w, int h);

private:
    FrameBuffer();
    bool BiltLimit(int &x1, int &y1, int &x0, int &y0, int &w, int &h);

public:
    int width;
    int height;

private:
    static FrameBuffer *instance;
    char *fbBuffer;
    int lineLength;
    int screenSize;
    int fd;
    int bitPerPixel;
};

class Window;

class Layer : public NonCopyable{
protected:
    Window *window;
public:
    Rect region;
    bool active_status;

public:
    Layer(Window *win, int left, int top, int right, int bottom);
    virtual ~Layer();

    virtual void Render(Bitmap *bitmap) = 0;
    virtual void set_active_status(bool status);

    virtual void MouseUp(Event &e);
    virtual void MouseDown(Event &e);
    virtual void MouseEnter(Event &e);
    virtual void MouseLeave(Event &e);
    virtual void MouseDrag(Event &e);

    virtual void EventHandler(Event &e);
};

class BackgroundLayer : public Layer{
public:
    BackgroundLayer(Window *win);
    ~BackgroundLayer();

    void set_active_status(bool status);

    void Render(Bitmap *bitmap);
    void MouseUp(Event &e);
    void MouseDown(Event &e);
    void MouseDrag(Event &e);

private:
    Color background_color;
    Color inner_border_color;

    Rect rect_left, rect_right, rect_top, rect_bottom;
    Point point_left_top, point_right_top;
    Point point_left_bottom, point_right_bottom;

    Rect title;
    Rect drag_region;
    bool mouse_drag;

};

class TitleLayer : public Layer {
public:
    TitleLayer(Window *win, const char *str);
    ~TitleLayer();

    void set_active_status(bool status);
    void Render(Bitmap *bitmap);

private:
    char *title;
    Bitmap* title_bitmap;
    FontManager *font;
};

class ButtonLayer : public Layer {
public:
    ButtonLayer(Window *win, ButtonLayerType type);
    ~ButtonLayer();

    void set_active_status(bool status);
    void MouseEnter(Event &e);
    void MouseLeave(Event &e);
    void MouseUp(Event &e);
    void Render(Bitmap *bitmap);

private:
    Bitmap *mouse_enter_bitmap;
    Bitmap *mouse_leave_bitmap;
    Bitmap *mouse_focus_out_bitmap;
    Bitmap *mouse_mouse_down_bitmap;
    Bitmap *current_bitmap;
    ButtonLayerType type;
};

class UIWindow;
class UIControl;
class ContainLayer : public Layer {
public:
    ContainLayer(Window *win, int w, int h, Rgb rgb, UIControl *root_control);
    ~ContainLayer();

    void Render(Bitmap *bitmap);

    virtual void EventHandler(Event &e);

    void Redraw(Rect *rect, Bitmap *canvas);
    void RenderUIWindow(Bitmap *canvas);

    // void SetControls(UIControl *root_control);

public:
    Rgb frontground_color;

private:
    int width,height;
    UIWindow *ui_window;
};

class WindowManager;

class Base {
public:
    int get_id();

protected:
    Base();

protected:
    int id;

private:
    static int counter;
};

class Window : public NonCopyable, public Base {
public:
    Window(WindowManager *wm, std::string str, WindowType type, 
           int w, int h, int x, int y);

    virtual ~Window();

    Rect GetWindowRect();
    virtual void Render() = 0;
    virtual void FocusOn();
    virtual void FocusOut();
    virtual void EventDispather(Event &e);

    void set_alpha(Byte alpha);
    void set_background_color(Rgb rgb);
public:
    WindowManager *wm;
    int root_x;
    int root_y;
    int width;
    int height;
    Bitmap *bitmap;
    std::string title;
    WindowType type;
    Byte alpha;
    Rgb background_color;
};

class Desktop : public Window {
public:
    Desktop(WindowManager *wm, std::string title, int w, int h, int x, int y);
    ~Desktop();

    void SetWallpaper(std::string path);
    void SetColor(Rgb color);
    void Render();
    void EventDispather(Event &e);
private:
    std::string wallpaper;
};

class UIControl;
class AppWindow : public Window{
public:
    AppWindow(WindowManager *wm, std::string title, int container_width,
              int container_height, int x, int y, Rgb color, UIControl *root_control);

    ~AppWindow();

    // void SetControls(UIControl *root_control);

    void EventDispather(Event &e);
    void Render();
    void FocusOn();
    void FocusOut();

private:
    void BorderRender();
private:
    std::list<Layer* > layers;
    ContainLayer *container_layer;
    BackgroundLayer *background_layer;
    ButtonLayer *close_button_layer;
    ButtonLayer *min_button_layer;
    ButtonLayer *max_button_layer;
    TitleLayer *title_layer;
    Layer* last_hold_on;
};


class InputManager : NonCopyable {
public:
    static InputManager& GetInstance();
    void Release();
    void Run(WindowManager *wm);
private:
    InputManager();
    void MouseMonitor(char *mouse_ev);
    void KeyboardMonitor(struct input_event *key_ev);

    void CheckCapslookAndShirt(struct input_event *key_ev);
    char ParseAcsii(unsigned int code);
    char ConvertCode(struct input_event *key_ev);

private:
    static const int kLeftButtonVal = 1;
    static const int kRightButtonVal = 2;

    static const int kKeyRelease = 0;
    static const int kKeyPress = 1;
    static const int kKeyKeepingPressed = 2;

    WindowManager *wm;

    //mouse member
    int clicks;
    int interval;
    int down_button;
    int last_button;
    long down_time;
    int mouse_fd;

    //keyboard member
    char capslook;
    char tolower;
    int keyboard_fd;

    static InputManager* instance;
};


class Config {
public:
    Config(std::string file_name);
    std::string operator[](const std::string &key);
    bool AddConfigFile(const std::string file_name);

    template<typename T>
        T value(const std::string &key);

private:
    bool IsCommentChar(char c);
    bool AnalyzLine(const std::string &line, std::string &key,
                    std::string &value);

    bool ParseConfig(const std::string &file_name);

    void value(const std::string &key, float &value);
    void value(const std::string &key, int &value);
    void value(const std::string &key, bool &value);
    void value(const std::string &key, std::string &value);

private:
    static const char kCommentChar = '#';
    std:: map<std::string, std::string> config_map;
};

class Panel;
class TaskIterm;


class WindowManager : public NonCopyable, Base {
public:
    WindowManager(std::string conf_file);
    ~WindowManager();
    void Run();

    AppWindow* CreateWindow(std::string title, int width, int height,
                            int x, int y, Rgb color, UIControl *root_control);

    void CloseWindow(Window *win);
    void ShowWindow(Window *win);
    void MinimizeWindow(Window *win);
    void RestoreWindow(Window *win);
    void MoveWindow(Window *win, int dx, int dy);
    void RedrawWindow(Window *win, Rect &relative_rect);
    void RedrawWindow(Window *win);
    void FocusOnWindow(Window *win);
    void PositionWindow(Window *win, WinPositionType type);

    void AddIcon(std::string title);
    void ArrangeIcon();
    void MinimizeAllWindow();

private:
    void InitDirtyRect();
    void AddDirtyRect(int left, int top, int right, int bottom);
    void inline AddDirtyRect(Rect &rect);
    void RenderDirtyRect();

    void RedrawScreen();
    Window* GetWindowByPos(Point &p);
    std::list<Window* >* GetWinZIndex(Window *win);
    std::list<Window* >* SelectZIndex(WinPositionType type);

    void  DispathMouseEvent(Window *win, int dx, int dy, 
                            int x, int y, EventType type);

    void  DispathKBEvent(Window *win, int x, int y, char code, EventType type);

    friend class InputManager;
    void KBEventHandler(char code, EventType event);
    void MouseEventHandler(int dx, int dy, EventType event);

public:
    Config conf;

private:
    static const int kMaxDirtyRect = 128;
    InputManager *input;
    FrameBuffer *fb;
    FontManager *font;

    Point cursor;
    Bitmap *cursor_bitmap;
    Window *last_hold_window;

    Bitmap *screen_bitmap;
    Desktop *desktop;
    Panel *panel;

    Window *active_window;
    std::map<int, Window* > window_map;

    std::list<Window* > z_index_alway_bottom;
    std::list<Window* > z_index_normal;
    std::list<Window* > z_index_alway_top;

    Rect dirty_list[kMaxDirtyRect];
    int dirty_rect_num;
    bool all_dirty; 
public:
    std::list<Window* > z_index_panel;
    std::map<int, WinPositionType> window_pos_map;
    std::list<Window* > minimize_win;

    std::list<Window *> icons;
    std::list<Window *> appWins;
};

class UISize { 
public:
    UISize(int cx, int cy);
    UISize(const Rect &rc);
    UISize();

public:
    int cx, cy;
};


class UIMargin {
public:
    ~UIMargin();
    UIMargin();
    UIMargin(int left, int top = 0, int right = 0, int bottom = 0);

public:
    int left;
    int top;
    int right;
    int bottom;
};

enum TextAlignment {
    kTextAlignmentLeft = 0x1,
    kTextAlignmentCenter = 0x2,
    kTextAlignmentRight = 0x3,

    kTextAlignmentTop = 0x40000,
    kTextAlignmentVCenter = 0x50000,
    kTextAlignmentBottom = 0x60000,
};

class UICanvas {
public:
    UICanvas(int width, int height, Color color);
    ~UICanvas();

    void FillRect(Rect &rc, Color color);
    void Rectangle(Rect &rc, Color color);
    void DrawBitmap(Bitmap *content, Rect &dst);
    void DrawImage(const std::string &filepath, Rect &dst, bool resize = false);
    void DrawText(const std::string text, const Rect &rc, Color color, int fontsize, int text_alignment);

public:
    Bitmap *bitmap;
};

enum Alignment {
    //绝对定位
    kAlignmentLeftTop,
    kAlignmentLeftCenter,
    kAlignmentLeftBottom,
    kAlignmentCenterTop,
    kAlignmentCenter,
    kAlignmentCenterBottom,
    kAlignmentRightTop,
    kAlignmentRightCenter,
    kAlignmentRightBottom,
    //相对定位
    kAlignmentLeft,
    kAlignmentRight,
    kAlignmentTop,
    kAlignmentBottom,
    kAlignmentFill
};


class UIWindow;
class UIControl {
public:
    UIControl();
    virtual ~UIControl();
    void SetAttribute(const char *name, const char *value);

    //name
    void SetControlName(const char* name);
    std::string GetControlName() const;

    //tag
    void SetTag(int tag);
    int GetTag() const;

    //margin
    void SetMargin(const UIMargin &margin);
    void SetMargin(int left, int top = 0, int right = 0, int bottom = 0);

    //size
    void SetSize(const UISize &size);
    void SetSize(int width, int height);
    UISize GetSize() const;

    //alignment
    void SetAlignment(Alignment type);
    Alignment GetAlignment() const;

    //parent
    void SetParent(UIControl *control);
    UIControl* GetParent() const;

    //visible
    void SetVisible(bool visible);
    bool IsVisible() const;

    //add/remove children
    //TODO:: Implement:  VBoxLayout, HBoxLayout: addLayout, addWidget; Windows : setLayout;
    void AddSubControl(UIControl *control);
    void RemoveSubControl(const std::string &name);

    //find by cursor
    UIControl* LookupMouseFocusedControl(const Point &point);

    //frame
    void SetRootFrame(const Rect *rect);
    void SetFrame(const Rect *rect);
    Rect GetFrame() const;

    //parent win
    void SetParentWin(UIWindow *window);
    UIWindow* GetParentWin(); 

    //need display and need layout
    void SetNeedDisplay();
    void SetNeedLayout();

    virtual void RenderSelf(const Rect *rect);
    virtual void ArrangeSelf(const Rect *parent_frame);

    //mouse event
    virtual bool OnMouseMessage(Event e);
    virtual void OnKeyMessage(Event e);

    virtual void OnMouseEntered(Event e);
    virtual void OnMouseExited(Event e);
    virtual bool OnLButtonDown(Event e);
    virtual bool OnLButtonUp(Event e);
    virtual bool OnMouseMove(Event e);
    virtual bool OnLButtonDoubleClicked(Event e);
    virtual void OnKeyDown(Event e);
    virtual void OnKeyUp(Event e);

private:
    void Render(const Rect *parent_rect);

    void Arrange(const Rect *parent_frame);
    void ArrangeChildren(const Rect *parent_frame);

    void SetParentVisibleRecursive(bool visible);

    bool IsMouseInControl(const Point &point);

    void DispatchMouseMessage(Event e);
    void DispatchKeyMessage(Event e);

    Alignment GetAlignmentByString(const char *value);

protected:
    std::vector<UIControl* > children_;
    UISize size_;
    Alignment alignment_type_;
    UIMargin margin_;
    Rect frame_;
    UIControl* parent_;
    UIWindow *parent_win_;
    std::string name_;
    int tag_;
    bool visible_;
    bool parent_visible_;

    friend class UIWindow;
};

class UIWindow {
public:
    UIWindow(ContainLayer *layer);
    ~UIWindow(); 

public:

    void UpdateLayout();
    void RenderLayout();
    void Invalidate(Rect *rc);
    void AddRootControl(UIControl *root_control);

    virtual void HandleMessage(Event &e);

    UICanvas* GetCanvas();
    void SetCanvas(UICanvas *canvas);

private:
    void Render(const Rect *rc);
    void DoUpdateLayout();
    void HandleMouseMessage(Event e);
    void HandleKBMessage(Event e);
    void SetCurrentMouseControl(UIControl *control, Event e);

private:
    bool is_mouse_in_;
    UIControl *current_mouse_control_;
    UIControl *root_control_;
    ContainLayer *layer;
    UICanvas *canvas_;
    Color background_color;
};

namespace Utils {

void AddToWindowList(std::list<Window* > &dst,const std::list<Window* > &src);

inline long NowTimeVal();

void Trim(std::string &str);

}

InputManager* InputManager::instance = NULL;
FrameBuffer* FrameBuffer::instance = NULL;
FontManager* FontManager::instance = NULL;
int Base::counter = 0;


//**************** !RGB ****************

inline Byte B(Rgb rgb) {
    return rgb;
}

inline Byte G(Rgb rgb) {
    return (unsigned short)rgb >> 8;
}

inline Byte R(Rgb rgb) {
    return rgb >> 16;
}

inline Rgb RGB(Byte red, Byte green, Byte blue) {
    return (Byte)blue | ((unsigned short)green << 8) 
        | ((unsigned int)red << 16);
}

//**************** !Rect ****************
int Rect::GetHeight() const {
    return bottom - top;
}

int Rect::GetWidth() const {
    return right - left;
}

int Rect::GetX() const {
    return left;
}

int Rect::GetY() const {
    return top;
}

bool Rect::IntersetRect(Rect &dst, const Rect &src1, const Rect &src2)
{
    dst.left = MAX(src1.left, src2.left);
    dst.top = MAX(src1.top, src2.top);
    dst.right = MIN(src1.right, src2.right);
    dst.bottom = MIN(src1.bottom, src2.bottom);

    if(dst.left >= dst.right) {
        return false;
    }
    if(dst.top >= dst.bottom) {
        return false;
    }
    return true;
}

Rect::Rect(): left(0), top(0), right(0), bottom(0) { }

void Rect::Inflate(int dx, int dy) {
    left = left - dx;
    if(left < 0) {
        left = 0;
    }

    right = right + dx;

    top = top - dy;
    if(top < 0) {
        top = 0;
    }

    bottom = bottom + dy;
}

Rect::Rect(int left, int top, int right, int bottom)
    :left(left), top(top), right(right), bottom(bottom) { }

    inline bool Rect::PointInRect(int x, int y) {
        return x >= left && x < right &&
            y >= top && y < bottom;
    }

//**************** !Point ****************

Point::Point() : x(0), y(0) { }

Point::Point(int x, int y) : x(x), y(y) { }

//**************** !Color ****************
inline Color Color::FromRGB(Rgb rgb) { 
    return Color( R(rgb), G(rgb), B(rgb) );
}

Color::Color(): b(0), g(0), r(0), alpha(0) { }

Color::Color(Byte r, Byte g, Byte b) 
    :b(b), g(g), r(r), alpha(0) { }

    Rgb Color::ToRGB() {
        return RGB(r, g, b);
    }


//**************** !Bitmap ****************
Bitmap::Bitmap(int width, int height) : width(width) , height(height) {
    if(width == 0 || height == 0) {
        data = NULL;
    }else {
        data = new Color[width * height];  
    }
};

Bitmap::~Bitmap() {
    delete [] data;
}

inline Color* Bitmap::GetBuffer() {
    return data;
}

inline Color& Bitmap::GetPixel(int x, int y) {
    return data[y * width + x];
}

inline void Bitmap::SetPixel(int x, int y, Color& src) {
    memcpy(data + y * width + x, &src, sizeof(Color) );
}

inline void Bitmap::SetAlphaPixel(int x, int y, Color &src, float alpha) {
    Color &dst = data[y * width + x];
    dst.r = alpha * (dst.r - src.r) + src.r;
    dst.g = alpha * (dst.g - src.g) + src.g;
    dst.b = alpha * (dst.b - src.b) + src.b;
}

bool Bitmap::BiltLimit(int &x1, int &y1, int &x0, int &y0, int &w, int &h) {
    if( x1 >= width || y1 >= height || x1 + w <= 0 || y1 + h <= 0) {
        return false;
    }

    if( x1 < 0) {
        x0 = x0 - x1;
        w = w + x1;
        x1 = 0;
    }
    if( y1 < 0) {
        y0 = y0 - y1;
        h = h + y1;
        y1 = 0;
    }

    if( x1 + w >= width) {
        w = width - x1;
        //-1
    }

    if( y1 + h >= height) {
        h = height - y1;
        //-1
    }

    if( !w || !h ) {
        return false;
    }
    return true;
}

bool Bitmap::BiltAlpha(int x1, int y1, Bitmap *src, int x0, int y0, 
                       int w, int h, int alpha) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }

    float depth = alpha / 255.0f;

    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {          	

            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            SetAlphaPixel(x1 + x, y1 + y, pixel, depth);
        }
    }
    return true;
}

bool Bitmap::Bilt(int x1, int y1, Bitmap *src, int x0, int y0, int w, int h) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }

    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {          	

            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            SetPixel(x1 + x, y1 + y, pixel);
        }
    }
    return true;
}

bool Bitmap::BiltFont(int x1, int y1, Bitmap *src, int x0, int y0, 
                      int w, int h) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }

    Color color = Color::FromRGB(BLACK);

    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {            

            Color &pixel = src->GetPixel(x0 + x, y0 + y);

            if( pixel.r == color.r && pixel.g == color.g &&
                pixel.b == color.b) {
                continue;
            }
            SetAlphaPixel(x1 + x, y1 + y, pixel, 1 - pixel.alpha / 255.0f);
            // if(pixel.alpha != 0) {
            // data[(y+y1) * width + (x+x1)].alpha = pixel.alpha;
            // }
        }
    }
    return true;
}

bool Bitmap::BiltPng(int x1, int y1, Bitmap *src, int x0, int y0, 
                     int w, int h) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }

    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {            

            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            // printf("%d\n", pixel.alpha);
            SetAlphaPixel(x1 + x, y1 + y, pixel, 1 - pixel.alpha / 255.0f);
        }
    }
    return true;
}


bool Bitmap::BiltMaskColor(int x1, int y1, Bitmap *src, int x0, int y0, 
                           int w, int h, Rgb mask) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }

    Color color = Color::FromRGB(mask);
    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {
            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            if( pixel.r == color.r && pixel.g == color.g
                && pixel.b == color.b) {
                continue;
            }
            SetPixel(x1 + x, y1 + y, pixel);
        }
    }
    return true;
}


inline int Bitmap::CheckValue(int value) {  
    return (value & ~0xff) == 0? value : value > 255? 255 : 0;  
}  

void Bitmap::AdjusctBrightContrast(int bright, int contrast, Byte threshold) {  
    if (bright == 0 && contrast == 0) {
        return;  
    }

    float bv = bright <= -255? -1.0f : bright / 255.0f;  
    if (bright > 0 && bright < 255)  {
        bv = 1.0f / (1.0f - bv) - 1.0f;  
    }

    float cv = contrast <= -255? -1.0f : contrast / 255.0f;  
    if (contrast > 0 && contrast < 255)  {
        cv = 1.0f / (1.0f - cv) - 1.0f;  
    }

    Byte values[256];  
    for (int i = 0; i < 256; i ++) {  
        int v = contrast > 0? CheckValue(i + (int)(i * bv + 0.5f)) : i;  
        if (contrast >= 255)  {
            v = v >= threshold? 255 : 0;  
        }
        else {
            v = CheckValue(v + (int)((v - threshold) * cv + 0.5f));  
        }
        values[i] = contrast <= 0? CheckValue(v + (int)(v * bv + 0.5f)) : v;  
    }  

    for(int y = 0; y < height; ++y) {
        for(int x = 0; x < width; ++x) {
            Color &color = GetPixel(x, y);
            color.b      = values[color.b];  
            color.g = values[color.g];  
            color.r       = values[color.r]; 
            SetPixel(x, y, color);
        }
    }
}  

void Bitmap::FillColor(Rgb rgb) {
    Color color = Color::FromRGB(rgb);
    color.alpha = 255;
    for(int y = 0; y < height; ++y) {
        for(int x = 0; x < width; ++x) {
            SetPixel(x, y, color);
        }
    }
}


bool Bitmap::DrawRect(Rect &rect, Color color) {     
    if(rect.right > width || rect.bottom > height) {
        return false;

    }

    for(int y = rect.top; y < rect.bottom; ++y) {
        for(int x = rect.left; x < rect.right; ++x) {
            SetPixel(x, y, color);
        }
    }
    return true;
}

bool Bitmap::DrawLine(Point &p1, Point &p2, Color color) {

    if(p1.x == p2.x) {

        int start = MIN(p1.y, p2.y);
        int end = MAX(p1.y, p2.y);

        for(int y = start; y < end; ++y) {
            SetPixel(p1.x, y, color);
        }
        return true;

    }else if(p1.y == p2.y) {

        int start = MIN(p1.x, p2.x);
        int end = MAX(p1.x, p2.x);

        for(int x= start; x < end; ++x) {
            SetPixel(x, p1.y, color);
        }
        return true;
    }
    return false;
}


//**************** !Image Bmp ****************
Bitmap* ImageUtils::LoadPNG( const char *file_name)
{
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    char buf[4];
    int i, j, temp, color_type, channels;
    png_bytep* row_pointers;

    fp = fopen(file_name, "rb");
    if(fp == NULL) {
        return NULL;
    }

    png_ptr  = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    info_ptr = png_create_info_struct(png_ptr);

    setjmp(png_jmpbuf(png_ptr)); 

    temp = fread(buf, 1, 4, fp);
    temp = png_sig_cmp((png_bytep)buf, (png_size_t)0, 4);

    if (temp != 0) {
        return NULL;
    }

    rewind(fp);
    png_init_io(png_ptr, fp);
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);

    channels = png_get_channels(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);
    row_pointers = png_get_rows(png_ptr, info_ptr);
    Bitmap* bitmap = NULL;

    if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
        bitmap = new Bitmap(png_get_image_width(png_ptr, info_ptr), 
                            png_get_image_height(png_ptr, info_ptr));
        Color* pos = bitmap->GetBuffer();
        temp = 4 * bitmap->width;
        for(i=0; i < bitmap->height; i++)
            for(j= 0; j < temp; j += 4) {
                pos->r = row_pointers[i][j]; // red
                pos->g = row_pointers[i][j + 1];// green
                pos->b = row_pointers[i][j + 2];// blue
                pos->alpha = row_pointers[i][j +3];
                if(pos->r != 0 && pos->alpha != 0) {
                }
                ++pos;
            }
    }
    if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB) {
        bitmap = new Bitmap(png_get_image_width(png_ptr, info_ptr), 
                            png_get_image_height(png_ptr, info_ptr));
        Color* pos = bitmap->GetBuffer();
        temp = 3 * bitmap->width;
        for(i = 0; i < bitmap->height; ++i) {
            for(j = 0; j < temp; j = j + 3) {
                pos->r = row_pointers[i][j]; // red
                pos->g = row_pointers[i][j + 1];// green
                pos->b = row_pointers[i][j + 2];// blue
                pos->alpha = 255;
                ++pos;
            }
        }   
    }
    png_destroy_read_struct(&png_ptr, &info_ptr, 0);
    fclose(fp);
    return bitmap;
}

Bitmap* ImageUtils::LoadJPG(const char *file_name)    
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPARRAY buffer;

    FILE *fp = fopen(file_name, "r");
    if(fp == NULL) {
        return NULL;
    }

    short int jpsyg;
    if( fread( &jpsyg, sizeof(short int), 1, fp ) ) {
        if ( jpsyg != -9985 ) { 
            return  NULL; 
        }
    }
    rewind(fp);

    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, fp);
    jpeg_read_header(&cinfo,true);
    jpeg_start_decompress(&cinfo);

    Bitmap* bitmap = new Bitmap(cinfo.output_width, cinfo.output_height);
    Color color;
    struct rgb_t {
        Byte r,g,b;
    };
    rgb_t buf[bitmap->width];

    buffer = (*cinfo.mem->alloc_sarray)( (j_common_ptr) &cinfo, 
                                         JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);

    int y = 0;
    while (cinfo.output_scanline < cinfo.output_height) {

        jpeg_read_scanlines(&cinfo, buffer, 1);

        memcpy(buf, *buffer, cinfo.output_width * cinfo.output_components);

        for(int x = 0; x < bitmap->width; ++x) {
            color.b = buf[x].b;
            color.g = buf[x].g;
            color.r = buf[x].r;
            color.alpha = 255;
            bitmap->SetPixel(x, y, color);
        }
        ++y;
        // cur_pos += cinfo.output_width;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(fp);

    return bitmap;
}



Bitmap* ImageUtils::LoadBMP(const char *file_path) {

    int width,height,line_size,y,offset,offset_bits;
    int16_t bit_count;
    FILE *fp;
    char file_type[2];

    fp = fopen(file_path, "rb");
    if(NULL == fp ) {
        return NULL;
    }

    fread(file_type, 2, 1, fp);
    if(memcmp(file_type, "BM", 2) != 0) {
        fclose(fp);
        return NULL;
    }

    fseek(fp, 0xa, SEEK_SET);
    fread(&offset_bits, sizeof(int), 1, fp);
    fseek(fp, 0x4, SEEK_CUR);
    fread(&width, sizeof(int), 1, fp);
    fread(&height, sizeof(int), 1, fp);
    fseek(fp, 0x2, SEEK_CUR);
    fread(&bit_count, sizeof(int16_t), 1, fp);

    if( 24 != bit_count) {
        fclose(fp);
        return NULL;
    }

    struct rgb_t {
        Byte b,g,r;
    };

    Bitmap *bitmap = new Bitmap(width, height);
    Color *cur_pos = bitmap->GetBuffer();
    rgb_t buf[width];
    line_size = width * 3;

    if(line_size % 4 != 0) {
        line_size = line_size + (4 - line_size % 4);
    }

    for(y = 0; y < height; ++y) {
        offset = offset_bits + line_size * (height - 1 - y );
        fseek(fp, offset, SEEK_SET);
        fread(&buf, width * sizeof(rgb_t), 1, fp);

        for(int x = 0; x < width; ++x) {
            cur_pos[x].b = buf[x].b;
            cur_pos[x].g = buf[x].g;
            cur_pos[x].r = buf[x].r;
            cur_pos[x].alpha = 255;
        }
        cur_pos = cur_pos + width;
    }

    fclose(fp);
    return bitmap; 
}

Bitmap* ImageUtils::LoadImage(const char* file_name) {
    static bool init_loadfun_list = false;
    static std::vector<std::pair<const char *, ImageUtils::LoadImageFun> > loadfuns;

    if (!init_loadfun_list) {
        loadfuns.push_back(std::make_pair("bmp", LoadBMP) );
        loadfuns.push_back(std::make_pair("jpg", LoadJPG));
        loadfuns.push_back(std::make_pair("png", LoadPNG));
        init_loadfun_list = true;
    }

    std::string ext = strrchr(file_name, '.') + 1;
    transform(ext.begin(), ext.end(), ext.begin(), tolower);
    for (size_t i = 0; i < loadfuns.size(); ++i) {
        std::pair<const char *,ImageUtils::LoadImageFun > &pair = loadfuns[i];
        if(!strcmp(ext.c_str(), pair.first) ) {
            if(pair.second) {
                return pair.second(file_name);
            }
        }
    }
    return NULL;
}

class UIResourceCache {
public:
    static UIResourceCache& GetInstance();
    bool GetImageByFilePath(const std::string &filepath, Bitmap **image);

private:
    UIResourceCache();
    ~UIResourceCache();
private:
    class Garbo {
    public:
        ~Garbo();
    };

    static Garbo release_;
    static UIResourceCache *instance_;
    std::map<std::string, Bitmap* > image_caches_;
};

UIResourceCache* UIResourceCache::instance_ = NULL;
UIResourceCache::Garbo UIResourceCache::release_;

UIResourceCache::UIResourceCache() {

}

UIResourceCache& UIResourceCache::GetInstance() {
    if(instance_ == NULL) {
        instance_ = new UIResourceCache();
    }
    return *instance_;
}

UIResourceCache::~UIResourceCache() {

    for (std::map<std::string, Bitmap* >::iterator it = image_caches_.begin();
         it != image_caches_.end(); ++it) {
        delete it->second;
    }
}

UIResourceCache::Garbo::~Garbo() {
    if(instance_ != NULL) {
        delete instance_;
        instance_ = NULL;
    }
}

bool UIResourceCache::GetImageByFilePath(const std::string &filepath, Bitmap **image) {

    if(image_caches_.find(filepath) == image_caches_.end() ) {
        bool find = false;
        Bitmap *bitmap = ImageUtils::LoadImage(filepath.c_str() );
        if(bitmap != NULL) {
            image_caches_[filepath] = bitmap;
            *image = bitmap;
            find = true;
        }
        return find;
    }else {
        *image = image_caches_[filepath];
        return true;
    }
}


Bitmap* ImageUtils::LoadImage(const char* file_name, int width, int height) {
    Bitmap *image = LoadImage(file_name);
    Bitmap *dst;
    if(image != NULL && image->width != width && image->height != height) {
        dst = ResizeImage(image, width, height);
        delete image;
    }else {
        dst = image;
    }
    return dst;
} 


//双线性插值图像缩放算法(OpenCV中默认使用)
Bitmap* ImageUtils::ResizeImage(Bitmap* src, int dst_width, int dst_height) {
    int w0 = src->width;
    int h0 = src->height;

    int w1 = dst_width;
    int h1 = dst_height;

    Bitmap *dst = new Bitmap(dst_width, dst_height);

    float fw = float(w0) / w1;
    float fh = float(h0) / h1;

    int y1,y2, x1,x2, x0,y0;
    float fx1,fx2, fy1, fy2;
    Color color;
    Color c1,c2,c3,c4;

    for(int y = 0; y < h1; ++y) {
        y0 = y * fh;
        y1 = int(y0);
        y2 = (y1 == h0 - 1 ? y1 : y1 + 1);

        fy1 = y1 - y0; 
        fy2 = 1.0f - fy1;

        for(int x = 0; x < w1; ++x) {
            x0 = x*fw;
            x1 = int(x0);

            x2 = (x1 == w0 - 1 ? x1 : x1 + 1);

            fx1 = y1 - y0;
            fx2 = 1.0f - fx1;

            float s1 = fx1 * fy1;
            float s2 = fx2 * fy1;
            float s3 = fx2 * fy2;
            float s4 = fx1 * fy2;

            c1 = src->GetPixel(x1,y1);
            c2 = src->GetPixel(x2,y1);
            c3 = src->GetPixel(x1,y2);
            c4 = src->GetPixel(x2,y2);

            color.r =  (Byte)(c1.r * s3) + (Byte)(c2.r * s4) + (Byte)(c3.r * s2) + (Byte)(c4.r * s1);
            color.g =  (Byte)(c1.g * s3) + (Byte)(c2.g * s4) + (Byte)(c3.g * s2) + (Byte)(c4.g * s1);
            color.b =  (Byte)(c1.b * s3) + (Byte)(c2.b * s4) + (Byte)(c3.b * s2) + (Byte)(c4.b * s1);
            color.alpha =  (Byte)(c1.alpha * s3) + (Byte)(c2.alpha * s4) + (Byte)(c3.alpha * s2) + (Byte)(c4.alpha * s1);

            dst->SetPixel(x, y, color);
        }
    }
    return dst;
}

//**************** !Font ****************

Font::Font(int w, int h, int left, int top) 
    :width(w), height(h) , left(left), top(top) {
        data = new Byte[w * h];
    }

Font::~Font() {
    delete [] data;
}

Byte* Font::GetBuffer() {
    return data;
}

void Font::Render(Bitmap *bitmap, Rgb rgb) {
    Color color = Color::FromRGB(rgb);
    int &x1 = left;
    int &y1 = top;
    Color pixel;

    for(int y = 0; y < height; ++y) {
        for(int x = 0; x < width; ++x) {
            Byte depth = data[y * width + x];
            if(y + y1 >= bitmap->height || x + x1 >= bitmap->width ) {
                continue;
            }
            pixel.b = color.b;
            pixel.g = color.g;
            pixel.r = color.r;
            pixel.alpha = depth;

            bitmap->SetPixel(x + x1, y + y1, pixel);
        }
    }
}


//**************** !FontManager ****************

wchar_t* FontManager::UTF8ToUnicode( const char *src) {

    Byte *p, t, save[20];

    int len = strlen(src)+1;
    wchar_t* buf = (wchar_t *)calloc(sizeof(wchar_t), len);

    for(int count = 0, i = 0, j = 0; i < len; ++i) {
        t = src[i];
        if(t == 0) {
            break;
        }
        if((t>>7) == 0) {// 0xxxxxxx
            buf[j] = t;
            ++j;
        } else if((t>>5) == 6) {// 110xxxxx
            count = 2;
        } else if((t>>4) == 14) {// 1110xxxx
            count = 3;
        } else if((t>>3) == 30) {// 11110xxx
            count = 4;
        } else if((t>>2) == 62) {// 111110xx
            count = 5;
        } else if((t>>1) == 126) {// 1111110x
            count = 6;
        }

        if(count > 0) {
            p = (Byte*)&src[i];
            for(int n = 0; n < count; ++n) {
                save[n] = *p++;
            }
            count = 0;
            buf[j] = CovertCode(save);
            memset(save, 0, sizeof(save));
            ++j;
        }
    }
    return buf;
}

FontManager& FontManager::GetInstance() {
    if(!instance) {
        instance = new FontManager();
    }
    return *instance;
}

FontManager::FontManager() {
    Config conf(kDefualtWmConfigFile);
    FT_Init_FreeType( &library );
    FT_New_Face( library, conf[kConfDefaultFont].c_str(), 0, &face );
}

void FontManager::Release() {
    FT_Done_Face(face);
    FT_Done_FreeType(library);
}

Font* FontManager::FtBitmapToFont(FT_Bitmap* bitmap, int left, int top) {

    Font *font = new Font(bitmap->width, bitmap->rows, left, top);
    for(int y = 0; y < bitmap->rows; ++y) {
        for(int x = 0; x < bitmap->width; ++x) {
            Byte *buffer = font->GetBuffer();
            int pos = y * bitmap->width + x;
            buffer[pos] = bitmap->buffer[pos];
        }
    }
    return font;
}

Bitmap* FontManager::DrawText(const char *text, int font_size, Rgb rgb)
{
    const wchar_t *str = UTF8ToUnicode(text);
    const int len = wcslen(str);

    FT_GlyphSlot slot = face->glyph;
    FT_Set_Pixel_Sizes(face, font_size, font_size);

    FT_Vector pen;
    pen.x = 0;
    pen.y = 0;
    Font* fonts[len];

    for(int n = 0; n < len; ++n) {

        FT_Set_Transform( face, 0, &pen);
        FT_Load_Char( face, str[n], FT_LOAD_RENDER );

        fonts[n] = FtBitmapToFont(&slot->bitmap, slot->bitmap_left,
                                  font_size - slot->bitmap_top);
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    Bitmap *bitmap = new Bitmap(slot->bitmap_left + slot->bitmap.width + 2,
                                font_size + 4 + font_size / 16);
    for(int n = 0; n < len; ++n) {
        fonts[n]->Render(bitmap, rgb);
        delete fonts[n];
    }
    return bitmap;
}


wchar_t FontManager::CovertCode(Byte *in) {

    wchar_t unicode;
    unicode = in[0];

    if (unicode >= 0xF0) {
        unicode = (wchar_t) (in[0] & 0x07) << 18;
        unicode |= (wchar_t) (in[1] & 0x3F) << 12;
        unicode |= (wchar_t) (in[2] & 0x3F) << 6;
        unicode |= (wchar_t) (in[3] & 0x3F);

    } else if (unicode >= 0xE0) {
        unicode = (wchar_t) (in[0] & 0x0F) << 12;
        unicode |= (wchar_t) (in[1] & 0x3F) << 6;
        unicode |= (wchar_t) (in[2] & 0x3F);

    } else if (unicode >= 0xC0) {
        unicode = (wchar_t) (in[0] & 0x1F) << 6;
        unicode |= (wchar_t) (in[1] & 0x3F);
    }
    return unicode;
}

//**************** !FrameBuffer ****************

FrameBuffer::FrameBuffer() {

    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    Config conf(kDefualtWmConfigFile);
    fd = open(conf[kConfFramebuffer].c_str(), O_RDWR);

    if( fd == -1) {
        printf("can not open fb!\n");
        exit(0);
    }

    if( ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) ) {
        printf("can not read fixed info\n");
        exit(0); 
    }

    if( ioctl(fd, FBIOGET_FSCREENINFO, &finfo) ) {
        printf("can not read variable info\n");
        exit(0);
    }
    screenSize = finfo.smem_len;
    fbBuffer = (char*) mmap(0, finfo.smem_len,
                            PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    if( fbBuffer == MAP_FAILED ) {
        printf("mmap Failed\n");
        exit(0);
    }

    lineLength = finfo.line_length;
    height = vinfo.yres;
    width = vinfo.xres;
    bitPerPixel = vinfo.bits_per_pixel;
}

FrameBuffer& FrameBuffer::GetInstance() {
    if(!instance) {
        instance = new FrameBuffer();
    }
    return *instance;
}

void FrameBuffer::Release() {
    if(fd == -1) {
        return;
    }

    close(fd);
    munmap(fbBuffer, screenSize);
    fd = -1;
}

bool FrameBuffer::BiltScreen(Bitmap *bitmap) {

    if( width != bitmap->width || height != bitmap->height) {
        return false;
    }

    for(int y = 0 ; y < bitmap->height; ++y) {
        for(int  x = 0; x < bitmap->width; ++x) {
            int loc =(x) *(bitPerPixel / 8 )  + (y) * lineLength;
            const Color pixel = bitmap->GetPixel(x, y);
            memcpy(fbBuffer + loc, &pixel, 3);
        }
    }
    return true;
}

bool FrameBuffer::BiltLimit(int &x1, int &y1, int &x0, int &y0, 
                            int &w, int &h) {

    if( x1 >= width || y1 >= height || x1 + w <= 0 || y1 + h <= 0) {
        return false;
    }

    if( x1 < 0) {
        x0 = x0 - x1;
        w = w + x1;
        x1 = 0;
    }
    if( y1 < 0) {
        y0 = y0 - y1;
        h = h + y1;
        y1 = 0;
    }

    if( x1 + w >= width) {
        w = width - x1;
        //-1
    }

    if( y1 + h >= height) {
        h = height- y1;
        //-1
    }

    if( !w || !h ) {
        return false;
    }
    return true;
}

bool FrameBuffer::Bilt(int x1, int y1, Bitmap *src, int x0, int y0, 
                       int w, int h) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }
    int loc = 0;
    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {
            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            loc = (x + x1) * bitPerPixel / 8 + (y + y1) *lineLength;
            memcpy(fbBuffer + loc, &pixel, sizeof(Pixel));
        }
    }
    return true;
}

bool FrameBuffer::BiltCursor(int x1, int y1, Bitmap *src, int x0, int y0,
                             int w, int h) {

    if(!BiltLimit(x1, y1, x0, y0, w, h) ) {
        return false;
    }
    int loc = 0;
    Color color = Color::FromRGB(WHITE);
    for(int y = 0; y < h; ++y) {
        for(int x = 0; x < w; ++x) {            
            Color &pixel = src->GetPixel(x0 + x, y0 + y);
            if( pixel.b == color.b && pixel.g == color.g &&
                pixel.r == color.r) {
                continue;
            }
            loc = (x + x1) * bitPerPixel / 8 + (y + y1) *lineLength;
            memcpy(fbBuffer + loc, &pixel, sizeof(Pixel));
        }
    }
    return true;
}

//**************** !Layer ****************

Layer::Layer(Window *win, int left, int top, int right, int bottom)
    :window(win), region(left, top, right, bottom), active_status(true) { }

    Layer::~Layer() {}

    void Layer::MouseUp(Event &e) { }

    void Layer::MouseDown(Event &e) { }

    void Layer::MouseEnter(Event &e) { }

    void Layer::MouseLeave(Event &e) { }

    void Layer::MouseDrag(Event &e)  { }

    void Layer::EventHandler(Event &e) {
        if(e.type == kWmLeftButtonUp) {
            MouseUp(e);
        }else if(e.type == kWmLeftButtonDown) {
            MouseDown(e);
        }else if(e.type == kWmMouseDragMove) {
            MouseDrag(e);
        }else if(e.type == kWmMouseEnter) {
            MouseEnter(e);
        }else if(e.type == kWmMouseLeave) {
            MouseLeave(e);
        }
    }

void Layer::set_active_status(bool status) {
    this->active_status = status;
}

//**************** !Base ****************
inline int Base::get_id() {
    return id;
}

Base::Base() {
    ++Base::counter;
    id = Base::counter;
}

//**************** !Window ****************
Window::Window(WindowManager *wm, std::string str, WindowType type, 
               int w, int h, int x, int y)
    :Base(), wm(wm), root_x(x), root_y(y), width(w), height(h), 
    title(str), type(type) ,alpha(0), background_color(255) {

        bitmap = new Bitmap(width, height);
    }

Window::~Window() {
    delete bitmap;
}

void Window::set_alpha(Byte alpha) {
    this->alpha = alpha;
}

void Window::set_background_color(Rgb rgb) {
    this->background_color = rgb;
}

void Window::EventDispather(Event &e) {
}

Rect Window::GetWindowRect() {
    Rect rect(root_x, root_y, root_x + width, root_y + height);
    return rect;
}

void Window::FocusOn() { }

void Window::FocusOut() { }


//**********StartMenu*********
class StartMenu : public Window {
public:
    StartMenu(WindowManager *wm, std::string str, 
              int w, int h, int x, int y);
    ~StartMenu();
    void EventDispather(Event &e);
    void Render();
};

StartMenu::StartMenu(WindowManager *wm, std::string str, int w, int h, int x, int y)
    : Window(wm, title, kAppIconWindow, w, h, x, y) {

    }

StartMenu::~StartMenu() {}

void StartMenu::Render() {}

void StartMenu::EventDispather(Event &e) {}



class AppIcon : public Window {
public:
    AppIcon(WindowManager *wm, std::string str,  int x, int y);
    ~AppIcon();
    void EventDispather(Event &e);
    void Render();
    void MouseDown(Event &e);
    void MouseUp(Event &e);
    void MouseDragMove(Event &e);
    void MouseDClick(Event &e);

private:
    Bitmap *icon;
    Bitmap *title;
    bool drag;
};

AppIcon::AppIcon(WindowManager *wm, std::string str, int x, int y)
    : Window(wm, str, kAppIconWindow, 75, 75, x, y), drag(false) {

        icon = ImageUtils::LoadImage("./ico.png");
        bitmap->Bilt(bitmap->width /2 - icon->width / 2, 
                     60 / 2 - icon->height / 2, icon, 0, 0, icon->width, icon->height);
        FontManager &font = FontManager::GetInstance();
        title = font.DrawText(str.c_str(), 14, WHITE);

        bitmap->Bilt(bitmap->width / 2 - title->width / 2,
                     60 + 15 / 2 - title->height / 2, 
                     title, 0, 0, title->width, title->height);
    }

void AppIcon::MouseDown(Event &e) {
    drag = true;
}
void AppIcon::MouseUp(Event &e) {
    drag = false;
}

void AppIcon::MouseDragMove(Event &e) {
    wm->MoveWindow(this, e.dx, e.dy);
}

void AppIcon::MouseDClick(Event &e) {
    // printf("DClick!!\n");
}

AppIcon::~AppIcon() {
    delete icon;
    delete title;
}

void AppIcon::Render() {}

void AppIcon::EventDispather(Event &e) {
    if(e.type == kWmLeftButtonDown) {
        MouseDown(e);
    }else if(e.type == kWmLeftButtonUp) {
        MouseUp(e);
    }else if(e.type == kWmMouseDragMove) {
        MouseDragMove(e);
    }else if(e.type == kWmLeftButtonDClick) {
        MouseDClick(e);
    }
}



//**************** !Pannel ****************
class TaskIterm : public Window {
public:
    TaskIterm(Panel *panel, Window* which_hidden, int x, int y);
    ~TaskIterm();

    void Render();
    void MouseEnter(Event &e);//dispath by Panel, insteaf of WindowManager
    void MouseLeave(Event &e);
    void MouseUp(Event &e);
    void EventDispather(Event &e);
private:
    Bitmap *icon;
    Bitmap *icon_enter;
    Panel *panel;
    Window *which_hidden;
public:
    int x;
};


class Panel : public Window {
public:
    Panel(WindowManager *wm, std::string title, int w, int h, int x, int y);
    ~Panel();
    void EventDispather(Event &e);
    void Render();
    void AddTaskItem(Window *win);
private:
    std::list<TaskIterm* > items;
    // Window *window;
    TaskIterm *last_hold_iterm;
};


Panel::Panel(WindowManager *wm, std::string title, int w, int h, int x, int y)
    : Window(wm, title, kPanelWindow, w, h, x, y) { 
        last_hold_iterm = NULL;
    }

Panel::~Panel() { }

void Panel::AddTaskItem(Window *win) {
    int size = items.size();
    TaskIterm *item = new TaskIterm(this, win, 20 + size  * 57 + root_x , root_y);
    items.push_back(item);
    wm->z_index_panel.push_front(item);
    wm->window_pos_map[item->get_id()] = kWinPanelItem;
    wm->RedrawWindow(item);
}

void Panel::EventDispather(Event &e) {

    std::list<TaskIterm *>::iterator iter = items.begin();
    std::list<TaskIterm *>::iterator end = items.end();
    bool handled = false;

    e.x = e.x + root_x;
    e.y = e.y + root_y;

    for(; iter != end; ++iter) {
        TaskIterm *item = *iter;
        Rect rect = item->GetWindowRect();
        if(rect.PointInRect(e.x, e.y) ) {
            if(e.type == kWmMouseMove) {
                if(last_hold_iterm != item) {
                    if(last_hold_iterm) {
                        e.type = kWmMouseLeave;
                        last_hold_iterm->MouseLeave(e);                   
                    }
                    e.type = kWmMouseEnter;
                    item->MouseEnter(e);
                }
                last_hold_iterm = item;
            }else if(e.type == kWmLeftButtonUp) {
                item->MouseUp(e);
            }
            handled = true;
            break;
        }
    }
    //mouse out of all iterms, must in the pannel

    if(!handled) {
        if(last_hold_iterm) {
            e.type = kWmMouseLeave;
            last_hold_iterm->MouseLeave(e);
            last_hold_iterm = NULL;
        }
    }
}

void Panel::Render() {

}


TaskIterm::TaskIterm(Panel *panel, Window *win, int x, int y) 
    :Window(wm, win->title, kPanelItemWindow, 55, 40, x, y + 2) ,
    panel(panel), which_hidden(win) {

        icon = new Bitmap(55, 40);
        Bitmap *icon_bitmap =  ImageUtils::LoadImage("./taskitem.png");
        icon->Bilt((icon->width - icon_bitmap->width) / 2,
                   (icon->height - icon_bitmap->height) / 2, 
                   icon_bitmap, 0, 0, icon_bitmap->width, icon_bitmap->height);
        delete icon_bitmap;


        icon_enter = new Bitmap(55, 40);
        icon_enter->FillColor(RGB(31, 82, 125) );
        Bitmap *enter_bitmap = ImageUtils::LoadImage("./taskitem.png");
        icon_enter->BiltPng(
                            (icon_enter->width - enter_bitmap->width) / 2,
                            (icon_enter->height - enter_bitmap->height) / 2,
                            enter_bitmap, 0, 0, 
                            enter_bitmap->width, enter_bitmap->height);
        delete enter_bitmap;
        // icon_enter->AdjusctBrightContrast(35, 0, 121);
        width = icon->width;
        height = icon->height;
        delete bitmap;
        bitmap = icon;
    }


void TaskIterm::MouseEnter(Event &e) {
    bitmap = icon_enter;
    width = icon_enter->width;
    height = icon_enter->height;
    panel->wm->RedrawWindow(this);
}

void TaskIterm::MouseLeave(Event &e) {
    bitmap = icon;
    width = icon->width;
    height = icon->height;
    panel->wm->RedrawWindow(this);
}

void TaskIterm::MouseUp(Event &e) {
    panel->wm->RestoreWindow(which_hidden);
}

void TaskIterm::Render() {

}

TaskIterm::~TaskIterm() {
    delete icon;
    delete icon_enter;
}

void TaskIterm::EventDispather(Event &e) {
}


//**************** !Desktop ****************
Desktop::Desktop(WindowManager *wm, std::string title, int w, int h, int x, 
                 int y) : Window(wm, title, kDesktopWindow, w, h, x, y){ }

Desktop::~Desktop() { }

void Desktop::SetWallpaper(std::string path) {
    Bitmap *pic = ImageUtils::LoadImage(path.c_str(), width, height);
    bitmap->Bilt(0, 0, pic, 0, 0, pic->width, pic->height);
    delete pic;
    wallpaper = path;
}

void Desktop::SetColor(Rgb color) {
    bitmap->FillColor(color);
    background_color = color;
}

void Desktop::Render() { }

void Desktop::EventDispather(Event &e) {
    if(e.type == kWmRightButtonDown) {
        wm->ArrangeIcon();
    }
}

//**************** !AppWindow ****************
AppWindow::AppWindow(WindowManager *wm, std::string title, 
                     int container_width, int container_height, 
                     int x, int y, Rgb color, UIControl *root_control) 

    :Window(wm, title, kApplicationWindow,
            container_width + 2 * kAppWindowBorder,
            container_height + kAppWindowBorder + 36, x, y) {

        background_layer = new BackgroundLayer(this);
        layers.push_back(background_layer);

        title_layer = new TitleLayer(this, title.c_str());
        layers.push_back(title_layer);

        min_button_layer = new ButtonLayer(this, kMinButton) ;
        layers.push_back(min_button_layer);

        close_button_layer = new ButtonLayer(this, kCloseButton);
        layers.push_back(close_button_layer);

        max_button_layer = new ButtonLayer(this, kMaxButton);
        layers.push_back(max_button_layer);

        container_layer = new ContainLayer(this, container_width, container_height, color, root_control);

        layers.push_back(container_layer);
        last_hold_on = NULL;
    }

AppWindow::~AppWindow() {
    std::list<Layer*>::iterator iter = layers.begin();
    std::list<Layer*>::iterator endIter = layers.end();

    for(; iter != endIter; ++iter) {
        delete *iter;
    }
}

void AppWindow::EventDispather(Event &e) {

    if(e.where == kWmKeyEvent) {
        container_layer->EventHandler(e);
        return;
    }

    if(e.type == kWmMouseEnter || e.type == kWmMouseLeave) {
        //TODO:: handler this event by AppWindow
        last_hold_on = NULL;
        return;

    }else if(e.type == kWmMouseDragMove) {
        background_layer->EventHandler(e);
        return;
    }

    std::list<Layer*>::iterator iter = layers.end();
    std::list<Layer*>::iterator begin = layers.begin();

    if(e.type == kWmMouseMove) {
        for(; iter != begin;) {
            --iter;
            Layer *layer = *iter;
            if(layer->region.PointInRect(e.x, e.y)) {
                layer->EventHandler(e);
                if(last_hold_on != layer) {
                    if(last_hold_on) {
                        e.type = kWmMouseLeave;

                        last_hold_on->EventHandler(e);
                    }
                    e.type = kWmMouseEnter;
                    layer->EventHandler(e);
                }
                last_hold_on = layer;
                break;
            }

        }
        return;
    }

    //up, click, down , double click
    for(; iter != begin;) {
        --iter;
        Layer *layer = *iter;
        if(layer->region.PointInRect(e.x, e.y)) {
            layer->EventHandler(e);
            break;
        }
    }
}

void AppWindow::Render() {
    std::list<Layer*>::iterator iter = layers.begin();
    std::list<Layer*>::iterator endIter = layers.end();
    for(; iter != endIter; ++iter) {
        Layer *layer = *iter;
        layer->Render(bitmap);
    }
}

void AppWindow::BorderRender() {
    std::list<Layer*>::iterator iter = layers.begin();
    std::list<Layer*>::iterator endIter = layers.end();

    for(; iter != endIter; ++iter) {
        Layer *layer = *iter;
        if(layer != container_layer) {
            layer->Render(bitmap);
        }
    }
}

void AppWindow::FocusOn() {
    std::list<Layer*>::iterator iter = layers.begin();
    std::list<Layer*>::iterator endIter = layers.end();

    for(; iter != endIter; ++iter) {
        (*iter)->set_active_status(true);
    }
    BorderRender();
}

void AppWindow::FocusOut() {

    std::list<Layer*>::iterator iter = layers.begin();
    std::list<Layer*>::iterator endIter = layers.end();

    for(; iter != endIter; ++iter) {
        (*iter)->set_active_status(false);
    }
    BorderRender();
}


//**************** !Utils ****************
namespace Utils {

void AddToWindowList(std::list<Window* > &dst,const std::list<Window* > &src) {
    std::list<Window* >::const_iterator iter = src.end();
    std::list<Window* >::const_iterator begin = src.begin();

    for(;iter != begin; ) {
        --iter;
        dst.push_front(*iter);
    }
}

inline long NowTimeVal() {
    struct timeval now;
    gettimeofday(&now, 0);
    return  ( (long ) now.tv_sec) * 1000 + (long) now.tv_usec / 1000; 
}

inline bool IsSpace(char c) {
    return ' ' == c || '\t' == c;
};

void Trim(std::string &str) {
    if(str.empty() ) {
        return;
    }
    int i = 0;
    int len = str.size();
    for(i = 0; i < len; ++i) {
        if(!IsSpace(str[i] ) ) {
            break;
        }
    }

    if( i == str.size() ) {
        str = "";
        return;
    }

    int start = i;

    for(i = len - 1; i >= 0; --i) {
        if(!IsSpace(str[i] ) ){
            break;
        }
    }

    str = str.substr(start, i - start + 1);
}

}

//**************** !WindowManager ****************

WindowManager::~WindowManager() {
    input->Release();
    std::map<int, Window* >::iterator iter = window_map.begin();
    std::map<int, Window* >::iterator end = window_map.end();
    for(; iter != end; ++iter) {
        Window *win = iter->second;
        CloseWindow(win);
    }

    delete cursor_bitmap;
    last_hold_window = NULL;
    active_window = NULL;

    delete cursor_bitmap;
    font->Release();
    fb->Release();

}

void WindowManager::Run() {
    input->Run(this);
}

void WindowManager::InitDirtyRect() {
    dirty_rect_num = 0;
    all_dirty = false;
}

inline void WindowManager::AddDirtyRect(Rect &rect) {
    AddDirtyRect(rect.left, rect.top, rect.right, rect.bottom);
}

void WindowManager::AddDirtyRect(int left, int top, int right, int bottom) {
    Rect *ptr;
    if( dirty_rect_num >= kMaxDirtyRect) {
        all_dirty = false;
        return;
    }

    for(int i = 0; i < dirty_rect_num; ++i) {

        ptr = &dirty_list[i];
        if( ptr->left < right && ptr->right > left &&
            ptr->top < bottom && ptr->bottom > top ) {

            if( ptr->left > left ) {
                AddDirtyRect( left, MAX( top, ptr->top ),
                              ptr->left, MIN(bottom, ptr->bottom) );
            }

            if(ptr->right<right) {
                AddDirtyRect(ptr->right, MAX(top, ptr->top),
                             right, MIN(bottom,ptr->bottom) );
            }

            if(ptr->top>top) {
                AddDirtyRect( left, top, right, ptr->top );
            }

            if(ptr->bottom<bottom) {
                AddDirtyRect( left, ptr->bottom, right, bottom );
            }

            return;
        }
    }

    ptr = &dirty_list[dirty_rect_num++];
    ptr->left = left;
    ptr->top = top;
    ptr->right = right;
    ptr->bottom = bottom;
}



void WindowManager::RenderDirtyRect() {

    if(dirty_rect_num >= kMaxDirtyRect) {
        RedrawScreen();
        return;
    }

    std::list<Window *> all_window;
    Utils::AddToWindowList(all_window, z_index_alway_bottom);
    Utils::AddToWindowList(all_window, z_index_normal);
    Utils::AddToWindowList(all_window, z_index_alway_top);
    Utils::AddToWindowList(all_window, z_index_panel);

    std::list<Window* >::iterator begin = all_window.begin();
    std::list<Window* >::iterator end = all_window.end();

    Rect dst, window_rect;
    for(int i = 0; i < dirty_rect_num; ++i) {

        Rect &dirty_rect = dirty_list[i];
        //consider use bitmap cache
        Bitmap *bitmap = new Bitmap(dirty_rect.right - dirty_rect.left, 
                                    dirty_rect.bottom - dirty_rect.top);

        for(std::list<Window *>::iterator iter = end; iter != begin; ) {
            --iter;
            Window* window = *iter;
            window_rect = window->GetWindowRect();
            if(Rect::IntersetRect(dst , dirty_rect, window_rect)) {

                if(window == desktop) {
                    bitmap->Bilt(dst.left - dirty_rect.left, 
                                 dst.top - dirty_rect.top, window->bitmap,
                                 dst.left - window->root_x, dst.top - window->root_y,
                                 dst.right - dst.left, dst.bottom - dst.top);

                }else if(window->type == kPanelItemWindow  || window->type == kAppIconWindow){
                    bitmap->BiltPng(dst.left - dirty_rect.left, 
                                    dst.top - dirty_rect.top, window->bitmap,
                                    dst.left - window->root_x, dst.top - window->root_y,
                                    dst.right - dst.left, dst.bottom - dst.top);

                }else {
                    bitmap->BiltAlpha(dst.left - dirty_rect.left, 
                                      dst.top - dirty_rect.top, window->bitmap,
                                      dst.left - window->root_x, dst.top - window->root_y,
                                      dst.right - dst.left, dst.bottom - dst.top, window->alpha);

                }


            }
        }

        fb->Bilt(dirty_rect.left, dirty_rect.top, bitmap, 
                 0, 0, bitmap->width, bitmap->height);

        delete bitmap;
    }
}

WindowManager::WindowManager(std::string conf_file) 
    : conf(conf_file) {

        fb = &FrameBuffer::GetInstance();
        font = &FontManager::GetInstance();
        input = &InputManager::GetInstance();

        int screen_width = fb->width;
        int screen_height = fb->height;
		//printf("%d %d\n", screen_width, screen_height);
        cursor.y = screen_height / 2;
        cursor.x = screen_width / 2;
        screen_bitmap= new Bitmap(screen_width, screen_height);

        desktop = new Desktop(this, "Desktop", screen_width, screen_height, 0, 0);
        desktop->SetColor(WHITE);
        desktop->SetWallpaper(conf[kConfWallpapper].c_str());

        active_window = desktop;
        last_hold_window = desktop;
        window_map[desktop->get_id()] = desktop;
        z_index_alway_bottom.push_front(desktop);

        panel = new Panel(this, "TaskPanel", screen_width, 42, 0, screen_height - 42);
        Color color(0, 58 ,107);
        panel->bitmap->FillColor(color.ToRGB() );
        panel->set_alpha(180);

        window_map[panel->get_id()] = panel;
        z_index_alway_top.push_front(panel);

        // StartMenu *start_menu = new StartMenu(this, "StartMenu", 600, 500, 0, screen_height - 42 - 500);
        // start_menu->bitmap->FillColor(RGB(0, 84, 157) );
        // window_map[start_menu->get_id()] = start_menu;
        // z_index_alway_top.push_front(start_menu);
        // panel->AddTaskItem(start_menu);

        Bitmap* title = font->DrawText("Hello World!!!", 36, RED);
        desktop->bitmap->BiltFont(screen_width / 2 - title->width / 2, screen_height / 2 - title->height / 2, 
                                  title, 0, 0, title->width, title->height);
        delete title;

        RedrawScreen();
        cursor_bitmap = ImageUtils::LoadImage(conf[kConfMouseCursor].c_str());    
        fb->BiltCursor(cursor.x, cursor.y, cursor_bitmap, 0, 0, cursor_bitmap->width,
                       cursor_bitmap->height);
        InitDirtyRect();
    }

Window* WindowManager::GetWindowByPos(Point &p) {
    std::list<Window *> all_window;
    Utils::AddToWindowList(all_window, z_index_alway_bottom);
    Utils::AddToWindowList(all_window, z_index_normal);
    Utils::AddToWindowList(all_window, z_index_alway_top);

    std::list<Window* >::iterator begin = all_window.begin();
    std::list<Window* >::iterator end = all_window.end();

    Rect rect;
    for(std::list<Window *>::iterator iter = begin; iter != end; ++iter) {
        Window* window = *iter;
        rect = window->GetWindowRect();
        if( p.x >= rect.left && p.x <= rect.right &&
            p.y >= rect.top && p.y <= rect.bottom) {
            return window;
        }
    }
    return NULL;
}

void WindowManager::RedrawScreen() {
    std::list<Window *> all_window;
    Utils::AddToWindowList(all_window, z_index_alway_bottom);
    Utils::AddToWindowList(all_window, z_index_normal);
    Utils::AddToWindowList(all_window, z_index_alway_top);
    Utils::AddToWindowList(all_window, z_index_panel);

    std::list<Window* >::iterator begin = all_window.begin();
    std::list<Window* >::iterator end = all_window.end();

    for(std::list<Window *>::iterator iter = end; iter != begin;) {
        --iter;
        Window* window = *iter;
        if(window == desktop){
            screen_bitmap->Bilt(window->root_x, window->root_y, window->bitmap,
                                0, 0, window->width, window->height);

        }else if(window->type == kPanelItemWindow || window->type == kAppIconWindow){
            screen_bitmap->BiltPng(window->root_x, window->root_y, window->bitmap,
                                   0, 0, window->width, window->height);

        }else {
            screen_bitmap->BiltAlpha(window->root_x, window->root_y, window->bitmap,
                                     0, 0, window->width, window->height, window->alpha);

        }
    }
    fb->BiltScreen(screen_bitmap);
}

AppWindow* WindowManager::CreateWindow(std::string title, int width, int height, 
                                       int x, int y, Rgb color, UIControl *root_control) {
    AppWindow* window = new AppWindow(this, title, width, height, x, y, color, root_control);
    window_map[window->get_id()] = window;
    window_pos_map[window->get_id()] = kWinNormal;
    window->Render();

    panel->AddTaskItem(window);
    appWins.push_back(window);
    return window;
}

void WindowManager::PositionWindow(Window *win, WinPositionType type) {
    WinPositionType old = window_pos_map[win->get_id()];
    if(old == type) {
        return;
    }
    window_pos_map[win->get_id()] = type;
    SelectZIndex(old)->remove(win);
    SelectZIndex(type)->push_front(win);
}

void WindowManager::MinimizeWindow(Window *win) {

    GetWinZIndex(win)->remove(win);
    if(active_window == win) {
        active_window = desktop;
        active_window->FocusOn();
    }
    if(last_hold_window == win) {
        last_hold_window = GetWindowByPos(cursor);
    }
    InitDirtyRect();
    Rect rect;
    if(active_window != desktop) {
        rect = active_window->GetWindowRect();
        AddDirtyRect(rect);
    }

    rect = win->GetWindowRect();
    AddDirtyRect(rect);

    minimize_win.push_front(win);

    RenderDirtyRect();
}

void WindowManager::RestoreWindow(Window *win) {
    std::list<Window *>::iterator iter = minimize_win.begin();
    std::list<Window *>::iterator end = minimize_win.end();
    if(win == NULL) {
        for(; iter!= end; ++iter) {
            ShowWindow(*iter);
            break;
        }
        minimize_win.remove(*iter);
    }else {
        bool handled = false;
        for(; iter!= end; ++iter) {
            if(*iter == win) {
                ShowWindow(*iter);
                minimize_win.remove(*iter);
                handled = true;
                break;
            }
        }
        if(!handled) {
            MinimizeWindow(win);
        }
    }
}


void WindowManager::CloseWindow(Window *win) {

    window_map.erase(win->get_id());

    GetWinZIndex(win)->remove(win);
    window_pos_map.erase(win->get_id());

    if(active_window == win) {
        active_window = z_index_normal.front();
        active_window->FocusOn();
    }

    if(last_hold_window == win) {
        last_hold_window = GetWindowByPos(cursor);
    }

    InitDirtyRect();

    Rect rect;
    if(active_window != desktop) {
        rect = active_window->GetWindowRect();
        AddDirtyRect(rect);
    }

    rect = win->GetWindowRect();
    AddDirtyRect(rect);

    delete win;
    RenderDirtyRect();
}

void WindowManager::MoveWindow(Window *win, int dx, int dy) {

    Rect rect = win->GetWindowRect();
    win->root_x += dx;
    win->root_y += dy;
    Rect rect2 = win->GetWindowRect();

    InitDirtyRect();
    AddDirtyRect(rect2);
    AddDirtyRect(rect);
    RenderDirtyRect();
}

void WindowManager::RedrawWindow(Window *win, Rect &relative_rect) {
    Rect absolute_rect(relative_rect.left + win->root_x - 50,
                       relative_rect.top + win->root_y,
                       relative_rect.right + win->root_x, 
                       relative_rect.bottom + win->root_y);
    // absolute_rect.print();
    InitDirtyRect();
    AddDirtyRect(absolute_rect);
    RenderDirtyRect();
    // ShowWindow(win);
    Rect rect(cursor.x, cursor.y, cursor.x + cursor_bitmap->width,  cursor.y + cursor_bitmap->width);
    Rect dst;
    if( Rect::IntersetRect(dst, absolute_rect, rect) ) {
        fb->BiltCursor(cursor.x, cursor.y, cursor_bitmap, 0, 0, 
                       cursor_bitmap->width, cursor_bitmap->height);
    }
}

void WindowManager::RedrawWindow(Window *win) {
    InitDirtyRect();
    Rect rect = win->GetWindowRect();
    AddDirtyRect(rect);
    RenderDirtyRect();
}

//select which z_index the win has be placed, need z_index_map
inline std::list<Window* >* WindowManager::GetWinZIndex(Window *win) {
    WinPositionType type = window_pos_map[win->get_id()];
    return SelectZIndex(type);
}

//select which z_index by type, not need z_index_map
inline std::list<Window* >* WindowManager::SelectZIndex(WinPositionType type) {
    std::list<Window* > *z_index = NULL;
    if(type == kWinNormal) {
        z_index = &z_index_normal;
    }else if(type == kWinAlwayOnBottom) {
        z_index = &z_index_alway_bottom;
    }else if(type == kWinAlwayOnTop) {
        z_index = &z_index_alway_top;
    }else if(type == kWinPanelItem) {
        z_index = &z_index_panel;
    }else{
        return NULL;
    }
    return z_index;
}

void WindowManager::AddIcon(std::string title) {
    int size = icons.size();
    int pos_x = (75 + 10) * (size / 7) + 10;
    int pos_y = (75 + 10) * (size % 7) + 10;
    AppIcon *icon = new AppIcon(this, title, pos_x,  pos_y);
    icons.push_back(icon);
    window_map[icon->get_id()] = icon;
    window_pos_map[icon->get_id()] = kWinAlwayOnBottom;
    ShowWindow(icon);
}

void WindowManager::ArrangeIcon() {

    std::list<Window *>::iterator iter = icons.begin();
    std::list<Window *>::iterator end = icons.end();
    int count = 0;
    for(; iter != end; ++iter) {
        Window* iconWin = *iter;
        int pos_x = (75 + 10) * (count / 7) + 10;
        int pos_y = (75 + 10) * (count % 7) + 10;
        MoveWindow(iconWin, pos_x - iconWin->root_x, pos_y - iconWin->root_y);
        ++count;
    }

}

void WindowManager::MinimizeAllWindow() {
    std::list<Window *>::iterator iter = appWins.begin();
    std::list<Window *>::iterator end = appWins.end();

    for(; iter != end; ++iter) {
        Window *win = *iter;
        MinimizeWindow(win);
    }
}

void WindowManager::FocusOnWindow(Window* win) {
    //swap the window to the list head
    if(win == active_window) {
        return;
    }

    if(win->type == kPanelItemWindow) {
        return;
    } 

    Window *foncus_out = active_window;
    foncus_out->FocusOut();
    InitDirtyRect();
    active_window = win;
    if(win != desktop) {
        std::list<Window* > &z_index = *GetWinZIndex(win);
        z_index.remove(win);
        WinPositionType type = window_pos_map[win->get_id()];
        if(type == kWinAlwayOnTop) {
            std::list<Window* >::iterator iter = 
                find(z_index_alway_top.begin(), z_index_alway_top.end(), desktop);
            z_index_alway_top.insert(iter, win);
        }else {
            z_index.push_front(win);
        }


        win->FocusOn();

        Rect rect = win->GetWindowRect();
        AddDirtyRect(rect);

        if(foncus_out != desktop) {
            rect = foncus_out->GetWindowRect();
            AddDirtyRect(rect);
        }
    } else {//if win == desktop, then foncus_out not be desktop, otherwise "win == active_window"
        Rect rect = foncus_out->GetWindowRect();
        AddDirtyRect(rect);
    }

    RenderDirtyRect();
}

void WindowManager::ShowWindow(Window *win) {
    GetWinZIndex(win)->push_front(win);
    FocusOnWindow(win);
}

void WindowManager::KBEventHandler(char code, EventType event) {
    if(code == -5 && event == kWmKeyUp) {
        RedrawScreen();
    }

    if(active_window != desktop) {
        DispathKBEvent(active_window, cursor.x, cursor.y, code, event);
    }
}

void  WindowManager::DispathKBEvent(Window *win, int x, int y, 
                                    char code, EventType type) {
    Event e;
    e.dx = 0;
    e.dy = 0;
    e.x = x - win->root_x;
    e.y = y - win->root_y;
    e.next_handler = true;
    e.type = type;
    e.code = code;
    e.where = kWmKeyEvent;
    win->EventDispather(e);
}

void  WindowManager::DispathMouseEvent(Window *win, int dx, int dy,
                                       int x, int y, EventType type) {
    Event e;
    e.dx = dx;
    e.dy = dy;
    e.code = '\0';
    e.x = x - win->root_x;
    e.y = y - win->root_y;
    e.next_handler = true;
    e.type = type;
    e.where = kWmMouseEvent;
    if(e.x >= 0 && e.y >= 0) {
        win->EventDispather(e);
    }
}

void WindowManager::MouseEventHandler(int dx, int dy, EventType event) {

    int old_cursor_x = cursor.x;
    int old_cursor_y = cursor.y;
    cursor.x += dx;
    cursor.y += dy;
	//printf("mouse %d %d\n", cursor.x, cursor.y);

    if(cursor.x < 0) {
        cursor.x = 0;
        dx = 0;
    }

    if(cursor.x >= screen_bitmap->width - 2) {
        cursor.x = screen_bitmap->width - 2;
        dx = 0;
    }

    if(cursor.y < 0) {
        cursor.y = 0;
        dy = 0;
    }
    if(cursor.y >= screen_bitmap->height - 2) {
        cursor.y = screen_bitmap->height - 2;
        dy = 0;
    }

    if(cursor.x == 0 && cursor.y == 0 && event == kWmLeftButtonDown) {
        RestoreWindow(NULL);
    }

    if(cursor.y == screen_bitmap->height - 2 &&  cursor.x == screen_bitmap->width - 2 
       && event == kWmLeftButtonDown) {
        MinimizeAllWindow();
    }

    Point p;
    p.x = cursor.x;
    p.y = cursor.y;

    Window *win = GetWindowByPos(p);

    if(event == kWmMouseMove) {
        if(win != last_hold_window) {
            if(last_hold_window) {
                DispathMouseEvent(last_hold_window, dx, dy,
                                  cursor.x, cursor.y, kWmMouseLeave);
            }
            DispathMouseEvent(win, dx, dy, cursor.x, cursor.y, kWmMouseEnter);
        }
        DispathMouseEvent(win, dx, dy, cursor.x, cursor.y, kWmMouseMove);

    }else if(event == kWmMouseDragMove) {

        DispathMouseEvent(active_window, dx, dy,
                          cursor.x, cursor.y, kWmMouseDragMove);
    }else { //Up, Down, Click, DClick
        if(event == kWmLeftButtonDown) {
            FocusOnWindow(win);
        }

        DispathMouseEvent(win, dx, dy, cursor.x, cursor.y, event);
    }

    InitDirtyRect();

    AddDirtyRect(old_cursor_x, old_cursor_y, 
                 old_cursor_x + cursor_bitmap->width, 
                 old_cursor_y + cursor_bitmap->height);

    RenderDirtyRect();

    fb->BiltCursor(cursor.x, cursor.y, cursor_bitmap, 0, 0, 
                   cursor_bitmap->width, cursor_bitmap->height);

    last_hold_window = win;

}

//**************** !ButtonLayer ****************
ButtonLayer::ButtonLayer(Window *win, ButtonLayerType type) 
    : Layer(win, 0 , 0, 0, 0) , type(type) {
        std::string enter_icon, leave_icon, focus_out_icon;
        if(type == kCloseButton) {
            enter_icon = window->wm->conf[kConfAppWinBtnCloseEnter];
            leave_icon = window->wm->conf[kConfAppWinBtnCloseLeave];
            focus_out_icon = window->wm->conf[kConfAppWinBtnCloseFocusOut];

            region.left = win->width - kAppWindowBorder - 48;
            region.right = win->width - kAppWindowBorder;
            region.top = 0;
            region.bottom = 24;

        }else if(type == kMinButton) {
            enter_icon = window->wm->conf[kConfAppWinBtnMinEnter];
            leave_icon = window->wm->conf[kConfAppWinBtnMinLeave];
            focus_out_icon = window->wm->conf[kConfAppWinBtnMinFocusOut];

            region.left = win->width - kAppWindowBorder - 48 - 2 - 24 - 2 - 24;
            region.right = win->width - kAppWindowBorder - 48 - 2 - 24;
            region.top = 0;
            region.bottom = 24;
        }else if(type == kMaxButton) {
            enter_icon = window->wm->conf[kConfAppWinBtnMaxEnter];
            leave_icon = window->wm->conf[kConfAppWinBtnMaxLeave];
            focus_out_icon = window->wm->conf[kConfAppWinBtnMaxFocusOut];

            region.left = win->width - kAppWindowBorder - 48 - 2 - 24;
            region.right = win->width - kAppWindowBorder - 48 - 2;
            region.top = 0;
            region.bottom = 24;
        }

        mouse_leave_bitmap = ImageUtils::LoadImage(leave_icon.c_str() );
        mouse_enter_bitmap = ImageUtils::LoadImage(enter_icon.c_str() );
        mouse_focus_out_bitmap = ImageUtils::LoadImage(focus_out_icon.c_str());
        current_bitmap = mouse_leave_bitmap;
    }

void ButtonLayer::set_active_status(bool status) {
    this->active_status = status;
    current_bitmap = status ? mouse_leave_bitmap : mouse_focus_out_bitmap;
    Render(window->bitmap);
}

void ButtonLayer::MouseEnter(Event &e) {
    current_bitmap = mouse_enter_bitmap;
    Render(window->bitmap);
    window->wm->RedrawWindow(window, region);

}

void ButtonLayer::MouseLeave(Event &e) {
    if(active_status) {
        current_bitmap = mouse_leave_bitmap;
    }else {
        current_bitmap = mouse_focus_out_bitmap;
    }
    Render(window->bitmap);
    window->wm->RedrawWindow(window, region);
}

void ButtonLayer::MouseUp(Event &e) {
    if(type == kMinButton) {
        //min
        window->wm->MinimizeWindow(window);
    }else if(type == kCloseButton) {

    }
}

void ButtonLayer::Render(Bitmap *bitmap) {
    bitmap->Bilt(region.left, region.top, current_bitmap, 0, 0,
                 current_bitmap->width, current_bitmap->height);
}

ButtonLayer::~ButtonLayer() {
    delete mouse_enter_bitmap;
    delete mouse_leave_bitmap;
}

//**************** !TitleLayer ****************
TitleLayer::TitleLayer(Window *win, const char *str) 
    :Layer(win, 24, kAppWindowBorder, 0, 0) {
        font = &FontManager::GetInstance();
        title = strdup(str);
        title_bitmap = font->DrawText(title, 14, DARKGRAY);
    }

void TitleLayer::Render(Bitmap *bitmap) {
    bitmap->BiltFont(region.left, region.top, title_bitmap, 0, 0, 
                     title_bitmap->width, title_bitmap->height);
}

void TitleLayer::set_active_status(bool status) {
    this->active_status = status;
    delete title_bitmap;
    title_bitmap = font->DrawText(title, 14, status ? WHITE : DARKGRAY);
}

TitleLayer::~TitleLayer() {
    free(title);
    delete title_bitmap;
}

//**************** !BackgroundLayer ****************
BackgroundLayer::BackgroundLayer(Window *win) 
    :Layer(win, 0, 0, win->width, win->height),

    rect_left(0, 0, kAppWindowBorder, win->height),
    rect_top(0, 0, win->width, kAppWindowBorder),
    rect_right(win->width - kAppWindowBorder, 0, win->width, win->height),
    rect_bottom(0, win->height - kAppWindowBorder, win->width, win->height),

    point_left_top(kAppWindowBorder, 36), 
    point_right_top(win->width - kAppWindowBorder - 1, 36),
    point_left_bottom(kAppWindowBorder, win->height - kAppWindowBorder - 1), 
    point_right_bottom(win->width - kAppWindowBorder - 1, win->height - kAppWindowBorder - 1),

    background_color(107, 173, 246),
    inner_border_color(81, 142, 207),

    title(kAppWindowBorder, kAppWindowBorder, win->width, 36),
    mouse_drag(false),
    drag_region(0, 0, win->width - 48 - 2 - 24 -2 - 24 - 1, 36) { }

    void BackgroundLayer::Render(Bitmap *bitmap) {
        if(active_status) {
            background_color.r = 107;
            background_color.g = 173;
            background_color.b = 246;

            inner_border_color.r = 81;
            inner_border_color.g = 142;
            inner_border_color.b = 207;

        }else {
            background_color.r = 235;
            background_color.g = 235;
            background_color.b = 235;

            inner_border_color.r = 215;
            inner_border_color.g = 215;
            inner_border_color.b = 215;
        }

        bitmap->DrawRect(rect_left, background_color);
        bitmap->DrawRect(rect_top, background_color);
        bitmap->DrawRect(rect_right, background_color);
        bitmap->DrawRect(rect_bottom, background_color);

        bitmap->DrawLine(point_left_top, point_left_bottom, 
                         inner_border_color);

        bitmap->DrawLine(point_left_bottom, point_right_bottom, 
                         inner_border_color);

        bitmap->DrawLine(point_right_top, point_right_bottom, 
                         inner_border_color);

        bitmap->DrawRect(title, background_color);
    }

void BackgroundLayer::set_active_status(bool status) {
    active_status = status;
}

void BackgroundLayer::MouseUp(Event &e) {
    mouse_drag = false;
}

void BackgroundLayer::MouseDown(Event &e) {
    if(e.x > drag_region.left && e.x < drag_region.right &&
       e.y > drag_region.top && e.y < drag_region.bottom) {
        mouse_drag = true;
    }
}

void BackgroundLayer::MouseDrag(Event &e)  {
    if(mouse_drag) {
        window->wm->MoveWindow(window, e.dx, e.dy);
    }
}

BackgroundLayer::~BackgroundLayer() {

}


//**************** !InputManager ****************
InputManager::InputManager() :
    clicks(0), interval(300), down_button(0), last_button(-1), down_time(0),
    mouse_fd(-1), capslook(0), tolower(1), keyboard_fd(-1) {

        Config conf(kDefualtWmConfigFile);

        mouse_fd = open(conf[kConfMouse].c_str(), O_RDONLY);
        if(mouse_fd < 0) {
            printf("open mouse error!\n");
            exit(0);
        }

        keyboard_fd = open(conf[kConfKeyBoard].c_str(), O_RDONLY);
        if(keyboard_fd < 0) {
            printf("open keyboard! error\n");
            exit(0);
        }
    }

InputManager& InputManager::GetInstance() {
    if(!instance) {
        instance = new InputManager();
    }
    return *instance;
}

void InputManager::Release() {
    if(mouse_fd != -1) {
        close(mouse_fd);
        mouse_fd = -1;
    }
}

void InputManager::Run(WindowManager *wm) {
    this->wm = wm;
    fd_set rset;
    FD_ZERO(&rset);

    char mouse_ev[6];
    struct input_event key_ev;
    int max_fd = MAX(mouse_fd, keyboard_fd);    
    last_button  = -1;
    down_time = Utils::NowTimeVal();

    while(1) {
        FD_SET(mouse_fd, &rset);
        FD_SET(keyboard_fd, &rset);

        int ret = select(max_fd + 1, &rset, NULL, NULL, NULL);
        if(ret == -1) {
            printf("input select error!\n");
            exit(0);
        }
        if(ret == 0 ) {
            continue;
        }

        if(FD_ISSET(mouse_fd, &rset) ) {

            if(read(mouse_fd, mouse_ev, sizeof(mouse_ev) ) >= 3 ) {
				// printf ("Button type = %d, X = %d, Y = %d.\n",

                  //  mouse_ev[0] & 0x07, mouse_ev[1], mouse_ev[2]);
				  //
                MouseMonitor(mouse_ev);
            }
        }

        if(FD_ISSET(keyboard_fd, &rset) ) {
            int size = sizeof(struct input_event);
            if(read(keyboard_fd, &key_ev, size) >= size ) {
				
                KeyboardMonitor(&key_ev);
            }
        }
    }
}

void InputManager::MouseMonitor(char *mouse_ev) {
    long end  = Utils::NowTimeVal();
    long diff = end - down_time;

	int tmpx = mouse_ev[1];
	int tmpy = mouse_ev[2];
	if(tmpx > 128) {
		tmpx = tmpx - 255;
	}
	if(tmpy > 128) {
		tmpy = tmpy - 255;
	}

    int dx = tmpx;
    int dy = -tmpy;

    int button = mouse_ev[0] & 0x07;
	//printf("%d %d\n", dx, dy);
				
    if(dx || dy) {

        if(button) {
            wm->MouseEventHandler(dx, dy, kWmMouseDragMove); 
        }else{
            wm->MouseEventHandler(dx, dy, kWmMouseMove);
        }
    }

    if(clicks &&  diff > interval ) {
        clicks = 0;
    }

    if( button == kLeftButtonVal && !( last_button == kLeftButtonVal) ) {

        wm->MouseEventHandler(dx, dy, kWmLeftButtonDown);
        if( down_button == kLeftButtonVal && diff <= interval) {
            wm->MouseEventHandler(dx, dy, kWmLeftButtonDClick);
        }
        down_time = end;
        down_button = kLeftButtonVal;

    }else if( (button != kLeftButtonVal) && last_button == kLeftButtonVal) {

        wm->MouseEventHandler(dx, dy, kWmLeftButtonUp);
        if( down_button == kLeftButtonVal &&  diff  < interval) {
            clicks++;
            wm->MouseEventHandler(dx, dy, kWmLeftButtonClick);
        }
    }

    if(button == kRightButtonVal) {
        wm->MouseEventHandler(dx, dy, kWmRightButtonDown);
    }

    last_button = button;
}

void InputManager::KeyboardMonitor(struct input_event *key_ev) {
    // printf("yes\n");
     //printf("code : %c\n", key_ev->code);
    if(key_ev->type == EV_KEY
       && (key_ev->value == kKeyRelease || key_ev->value == kKeyPress
           || key_ev->value == kKeyKeepingPressed) ) {
        char code = ConvertCode(key_ev);
        if(code != '\0') {
            EventType event;
            if(key_ev->value == kKeyRelease) {
                event = kWmKeyUp;
            }else if(key_ev->value == kKeyPress) {
                event = kWmKeyDown;
            }else {
                event = kWmKeyKeep;
            }
            wm->KBEventHandler(code, event);
        }
    }
}

void InputManager::CheckCapslookAndShirt(struct input_event *key_ev) {
    unsigned int code = key_ev->code;

    if( code == LEFTSHIFT || code == RIGHTSHIFT) {
        if( key_ev->value == kKeyPress || key_ev->value == kKeyKeepingPressed) {
            tolower = capslook ? 1 : 0;
        }else if(key_ev->value == kKeyRelease) {
            tolower = capslook ? 0 : 1;
        }
    }else if( code == CAPSLOCK && key_ev->value == kKeyRelease) {
        capslook = !capslook;
        tolower = capslook ? 0 : 1;
    }
}

char InputManager::ParseAcsii(unsigned int code) {
    struct parse_key *p;
    for(p = acsii; p->key != '\0'; ++p) {
        if(p->value == code) {
            return p->key;
        }
    }
    return '\0';
}

char InputManager::ConvertCode(struct input_event *key_ev) {
    CheckCapslookAndShirt(key_ev);
    char ret = ParseAcsii(key_ev->code);
    if(ret != '\0' && ret >= 'A' && ret <= 'Z') {
        ret = tolower ? ret - 'A' + 'a' : ret;
    }
    return ret;
}


inline bool Config::IsCommentChar(char c) {
    return c == kCommentChar;
}

bool Config::AnalyzLine(const std::string &line, 
                        std::string &key, std::string &value) {
    if(line.empty() ) {
        return false;
    }
    int start = 0, end = line.size() - 1, pos;

    if( (pos = line.find(kCommentChar) ) != -1) {
        if(pos == 0) {
            return false;
        }
        end = pos - 1;
    }

    std::string new_line = line.substr(start, start + 1 - end);

    if( (pos = new_line.find('=') ) == -1) {
        return false;
    }

    key = new_line.substr(0, pos);
    value = new_line.substr(pos + 1, end + 1 - (pos + 1) );

    Utils::Trim(key);
    if(key.empty() ) {
        return false;
    }

    Utils::Trim(value);
    return true;
}

bool Config::ParseConfig(const std::string &file_name) {
    config_map.clear();
    std::ifstream file(file_name.c_str() );

    if(!file) {
        return false;
    }

    std::string line, key, value;
    while(std::getline(file, line) ) {
        if( AnalyzLine(line, key, value) ) {
            config_map[key] = value;
        }
    }

    file.close();
    return true;
}

Config::Config(std::string file_name) {
    ParseConfig(file_name);
}

bool Config::AddConfigFile(const std::string file_name) {
    return ParseConfig(file_name);
}

std::string Config::operator[](const std::string &key) {
    return config_map[key];
}

template<typename T>
T Config::value(const std::string &key){
    T tmp;
    value(key, tmp);
    return tmp;
}

void Config::value(const std::string &key, float &value) {
    value = atof(config_map[key].c_str());
}

void Config::value(const std::string &key, int &value) {
    value = atoi(config_map[key].c_str());
}

void Config::value(const std::string &key, bool &value) {
    std::string tmp = config_map[key];
    value = (tmp == "1" || tmp == "true");
}

void Config::value(const std::string &key, std::string &value) {
    value = config_map[key];
}


template<typename TP1, typename TP2>  
class IDelegate  {  
public:  
    virtual ~IDelegate() { }  
    virtual bool isType( const std::type_info& _type) = 0;  
    virtual void invoke( TP1 p1, TP2 p2 ) = 0;  
    virtual bool compare( IDelegate<TP1, TP2> *_delegate) const = 0;  
};  

template<typename TP1, typename TP2>  
class CStaticDelegate : public  IDelegate<TP1, TP2>   {  
public:  
    typedef void (*Func)( TP1 p1, TP2 p2 );  

    CStaticDelegate (Func _func) : mFunc(_func) { }  

    virtual bool isType( const std::type_info& _type) { 
        return typeid( CStaticDelegate<TP1, TP2> ) == _type; 
    }  

    virtual void invoke( TP1 p1, TP2 p2 )  {  
        mFunc( p1, p2 );  
    }  

    virtual bool compare( IDelegate<TP1, TP2> *_delegate) const  {  
        if (0 == _delegate ||
            !_delegate->isType(typeid(CStaticDelegate <TP1, TP2>)) ) {
            return false;
        }
        CStaticDelegate <TP1, TP2> * cast =
            static_cast<CStaticDelegate <TP1, TP2> *>(_delegate);  

        return cast->mFunc == mFunc;  
    }

private:  
    Func mFunc;  
};  


template <typename T, typename TP1, typename TP2>  
class CMethodDelegate : public  IDelegate <TP1, TP2>   {  
public:  
    typedef void (T::*Method)( TP1 p1, TP2 p2 );  

    CMethodDelegate(T * _object, Method _method) 
        : mObject(_object), mMethod(_method) { }  

    virtual bool isType( const std::type_info& _type) { 
        return typeid( CMethodDelegate <T, TP1, TP2> ) == _type; 
    }  

    virtual void invoke( TP1 p1, TP2 p2 ) {  
        (mObject->*mMethod)( p1, p2 );  
    }  

    virtual bool compare(  IDelegate <TP1, TP2>  * _delegate) const  {  
        if (0 == _delegate || 
            !_delegate->isType(typeid(CMethodDelegate <T, TP1, TP2>)) ) {
            return false;
        }

        CMethodDelegate <T, TP1, TP2>  * cast = 
            static_cast<  CMethodDelegate <T, TP1, TP2>  * >(_delegate);  

        return cast->mObject == mObject && cast->mMethod == mMethod;  
    } 

private:  
    T * mObject;  
    Method mMethod;  
};  

    template   <typename TP1, typename TP2>  
inline  IDelegate <TP1, TP2>* newDelegate( void (*_func)( TP1, TP2) )  
{  
    return new CStaticDelegate <TP1, TP2>  (_func);  
}  

    template <typename T, typename TP1, typename TP2>  
inline  IDelegate <TP1, TP2>* newDelegate(T * _object, 
                                          void (T::*_method)(TP1, TP2) )  
{  
    return new CMethodDelegate  <T, TP1, TP2>  (_object, _method);  
}  

template   <typename TP1, typename TP2>  
class CMultIDelegate  {  
public:  
    typedef IDelegate<TP1, TP2>  Delegate;  

    typedef typename std::list<Delegate*> ListDelegate;  
    typedef typename ListDelegate::iterator ListDelegateIterator;  
    typedef typename ListDelegate::const_iterator ConstListDelegateIterator;  

    CMultIDelegate () { }  

    ~CMultIDelegate () { 
        clear();
    }  

    bool empty() const  {  
        for (ConstListDelegateIterator iter = mListDelegates.begin();
             iter!=mListDelegates.end(); ++iter) {  
            if (*iter) return false;  
        }  
        return true;  
    }

    void clear() {  
        for (ListDelegateIterator iter=mListDelegates.begin(); 
             iter!=mListDelegates.end(); ++iter)  {  
            if (*iter) {  
                delete (*iter);  
                (*iter) = 0;  
            }  
        }  
    }  

    CMultIDelegate  <TP1, TP2> & operator+=(Delegate* _delegate) {  
        for (ListDelegateIterator iter=mListDelegates.begin(); 
             iter!=mListDelegates.end(); ++iter) {  
            if ((*iter) && (*iter)->compare(_delegate) ) {  
                delete _delegate;  
                return *this;  
            }  
        }  
        mListDelegates.push_back(_delegate);  
        return *this;  
    }  

    CMultIDelegate  <TP1, TP2> & operator-=(Delegate* _delegate)  {  
        for (ListDelegateIterator iter=mListDelegates.begin();
             iter!=mListDelegates.end(); ++iter) {  
            if ((*iter) && (*iter)->compare(_delegate) ) {  
                if ((*iter) != _delegate) delete (*iter);  
                (*iter) = 0;  
                break;  
            }  
        } 

        delete _delegate;  
        return *this;  
    }  

    void operator()( TP1 p1, TP2 p2 ) {  
        ListDelegateIterator iter = mListDelegates.begin();  
        while (iter != mListDelegates.end() ) {  
            if (0 == (*iter) ) {  
                iter = mListDelegates.erase(iter);  
            } else {  
                (*iter)->invoke( p1, p2 );  
                ++iter;  
            }  
        }  
    } 

private:  
    CMultIDelegate (const CMultIDelegate  <TP1, TP2> & _event);  
    CMultIDelegate<TP1, TP2> & operator=(const CMultIDelegate<TP1, TP2> & _event);  

private:  
    ListDelegate mListDelegates;  
};


#define slot public
#define emit

template<class ParamType>
class ISlot {

public:
    virtual void Execute(ParamType param) = 0;
    virtual ~ISlot() { };
    virtual  bool Compare(ISlot *slot_imp) const = 0;
};

template<class ObjectType, class ParamType>
class SlotImp : public ISlot<ParamType> {

    typedef void (ObjectType::*FunType)(ParamType);

public:
    SlotImp(ObjectType *obj, FunType func) : obj(obj), func(func) { }

    void Execute(ParamType param) {
        (obj->*func)(param);
    }

    bool Compare(ISlot<ParamType> *slot_imp) const {

        if(slot_imp && typeid(slot_imp) == typeid(SlotImp<ObjectType, ParamType>) ) {
            SlotImp<ObjectType, ParamType> *static_slot_imp =
                static_cast< SlotImp<ObjectType, ParamType> * >(slot_imp);

            return static_slot_imp->obj == obj && static_slot_imp->func == func;
        }
        return false;
    }

private:
    ObjectType* obj;
    FunType func;
};

template<class ParamType>
class Slot {

public:
    template<class ObjectType>
    Slot(ObjectType *obj, void (ObjectType::*func)(ParamType) ) {
        pSlotBase = new SlotImp<ObjectType, ParamType>(obj, func);
    }

    ~Slot() {
        delete pSlotBase;
    }

    void Execute(ParamType param) {
        pSlotBase->Execute(param);
    }

    ISlot<ParamType>* GetSlotBase() const {
        return pSlotBase;
    }   

    bool Compare(Slot<ParamType> *slots) const{
        return pSlotBase->Compare(slots->GetSlotBase() );
    }

private:
    ISlot<ParamType> *pSlotBase;
};

template<class ParamType>
class Signal {
private:
    typedef typename std::list<Slot<ParamType >* >::iterator SlotListIter;

public:
    template<class ObjectType>
    bool Bind(ObjectType* obj, void (ObjectType::*func)(ParamType)) {

        SlotListIter iter = slots.begin();
        SlotListIter end = slots.end();

        for (; iter != end; ++iter) {
            Slot<ParamType >* tmp = *iter;
            if (tmp->Compare(tmp)) {
                return false;
            }
        }
        slots.push_back(new Slot<ParamType>(obj, func));
        return true;
    }

    template<class ObjectType>
    bool UnBind(ObjectType* obj, void (ObjectType::*func)(ParamType)) {

        SlotListIter iter = slots.begin();
        SlotListIter end = slots.end();

        for (; iter != end; ++iter) {
            Slot<ParamType >* tmp = *iter;
            if (tmp->Compare(tmp)) {
                slots.erase(iter);
                delete tmp;
                return true;
            }
        }
        return false;
    }

    Signal() { };

    ~Signal() {
        SlotListIter iter = slots.begin();
        SlotListIter end = slots.end();

        for (; iter != end; ++iter) {
            delete (*iter);
        }
    }

    void operator ()(ParamType param) {
        SlotListIter iter = slots.begin();
        SlotListIter end = slots.end();

        for (; iter != end; ++iter) {
            (*iter)->Execute(param);
        }
    }

private:
    std::list< Slot<ParamType >* > slots;
};

class UIObject {
public:
    template<typename Sender, typename Signal, typename Receiver, typename Slot>
        static void Connect(Sender *sender, Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt);

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
        void Connect(Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt);

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
        static void Disconnect(Sender *sender, Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt);

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
        void Disconnect(Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt);

};

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
inline void UIObject::Connect(Sender *sender, Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt)
{
    (sender->*sig).Bind(receiver, slt);
}

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
inline void UIObject::Connect(Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt)
{
    Sender *sender = static_cast<Sender*>(this);
    (sender->*sig).Bind(receiver, slt);
}

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
inline void UIObject::Disconnect(Sender *sender, Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt)
{
    (sender->*sig).UnBind(receiver, slt);
}

    template<typename Sender, typename Signal, typename Receiver, typename Slot>
inline void UIObject::Disconnect(Signal Sender::*sig, Receiver *receiver, Slot Receiver::*slt)
{
    Sender *sender = static_cast<Sender*>(this);
    (sender->*sig).UnBind(receiver, slt);
}

UISize::UISize() {
    cx = cy = 0;
}

UISize::UISize(int _cx, int _cy) {
    cx = _cx;
    cy = _cy;
}


UISize::UISize(const Rect &rc) {
    cx = rc.GetWidth();
    cy = rc.GetHeight();
}



UIMargin::~UIMargin() {

} 

UIMargin::UIMargin() {
    left = top = right = bottom = 0;
}

UIMargin::UIMargin(int left, int top, int right, int bottom) 
    : left(left), top(top), right(right), bottom(bottom) {

    }

UICanvas::UICanvas(int _width, int _height, Color color) {
    bitmap = new Bitmap(_width, _height);
    Rgb rgb = color.ToRGB();
    bitmap->FillColor(WHITE);
}

UICanvas::~UICanvas() {
    delete bitmap;
}

void UICanvas::FillRect(Rect &rc, Color color) {
    bitmap->DrawRect(rc, color);
}

void UICanvas::Rectangle(Rect &rc, Color color) {
    Point p1(rc.left, rc.top);
    Point p2(rc.right, rc.top);
    Point p3(rc.left, rc.bottom);
    Point p4(rc.right, rc.bottom);

    bitmap->DrawLine(p1, p2, color);
    bitmap->DrawLine(p3, p4, color);
    bitmap->DrawLine(p1, p3, color);
    bitmap->DrawLine(p2, p4, color);
}

void UICanvas::DrawBitmap(Bitmap *content, Rect &dst) {
    int height = content->height < dst.GetHeight() ? content->height : dst.GetHeight();
    int width = content->width < dst.GetWidth() ? content->width : dst.GetWidth();

    bitmap->Bilt(dst.left, dst.top, content, 0, 0, width, height);
}

void UICanvas::DrawImage(const std::string &filepath, Rect &dst, bool resize) {
    Bitmap *image = NULL;
    if(!resize) {
        image = ImageUtils::LoadImage(filepath.c_str());
    }else {
        image = ImageUtils::LoadImage(filepath.c_str(), dst.GetWidth(), dst.GetHeight() );
    }

    int height = image->height < dst.GetHeight() ? image->height : dst.GetHeight();
    int width = image->width < dst.GetWidth() ? image->width : dst.GetWidth();

    bitmap->BiltPng(dst.left, dst.top, image, 0, 0, width, height);
    delete image;
}


void UICanvas::DrawText(const std::string text, const Rect &dst, Color color, int fontsize,
                        int text_alignment = kTextAlignmentLeft | kTextAlignmentTop) {

    FontManager &font_manager = FontManager::GetInstance();
    Bitmap *font = font_manager.DrawText(text.c_str() , fontsize, color.ToRGB() );

    int height = font->height < dst.GetHeight() ? font->height : dst.GetHeight();
    int width = font->width < dst.GetWidth() ? font->width : dst.GetWidth();

    int left = dst.left, top = dst.top;

    int horizontal = text_alignment & 0xFFFF;
    int vertical =  text_alignment & 0xFFFF0000;

    if(horizontal == kTextAlignmentLeft) {
        left = dst.left;
    }else if(horizontal == kTextAlignmentCenter) {
        left = dst.left + (dst.GetWidth() - font->width) / 2;
    }else if(horizontal == kTextAlignmentRight) {
        left = dst.right - font->width;
    }

    if(vertical == kTextAlignmentTop) {
        top = dst.top;
    }else if(vertical == kTextAlignmentVCenter) {
        top = dst.top + (dst.GetHeight() - font->height) / 2;
    }else if(vertical == kTextAlignmentBottom) {
        top = dst.bottom - font->height;
    }

    bitmap->BiltFont(left , top, font, 0, 0, width, height); 
    delete font;
}


//**************** !ContainLayer ****************
ContainLayer::ContainLayer(Window *win, int w, int h, Rgb color, UIControl *root_control) 
    :Layer(win, kAppWindowBorder + 1, 36, win->width - kAppWindowBorder - 2, win->height - kAppWindowBorder - 2),
    width(w), height(h), frontground_color(color), ui_window(NULL) {
        if(root_control != NULL) {
            ui_window = new UIWindow(this);
            ui_window->AddRootControl(root_control);
        }
    }

ContainLayer:: ~ContainLayer() {
    delete ui_window;
}

void ContainLayer::Render(Bitmap *bitmap) {
    if(ui_window) {
        ui_window->RenderLayout();

    }else {
        Bitmap *blank = new Bitmap(width, height);
        blank->FillColor(frontground_color);

        FontManager &font = FontManager::GetInstance();
        Bitmap *text = font.DrawText("Not Content", 16, RED);
        blank->BiltFont( (width - text->width) / 2, (height - text->height) / 2,
                         text, 0, 0, text->width, text->height);

        window->bitmap->Bilt(region.left, region.top, blank, 0, 0, blank->width, blank->height);

        delete text;
        delete blank;
    }
}

void ContainLayer::EventHandler(Event &e) {
    if(ui_window) {
        e.x = e.x - region.left;
        e.y = e.y - region.top;
        ui_window->HandleMessage(e);
    }
}

void ContainLayer::RenderUIWindow(Bitmap *canvas)  {
    window->bitmap->Bilt(region.left, region.top,
                         canvas, 0, 0, canvas->width, canvas->height);
}

void ContainLayer::Redraw(Rect *rc, Bitmap *canvas) {

    window->bitmap->Bilt(rc->left + region.left, rc->top + region.top,
                         canvas, rc->left , rc->top, rc->GetWidth(), rc->GetHeight());

    Rect rect(rc->left + region.left, rc->top + region.top,
              rc->right + region.left, rc->bottom + region.top);

    window->wm->RedrawWindow(window, rect);
}

UICanvas* UIWindow::GetCanvas() {
    return canvas_;
}

void UIWindow::SetCanvas(UICanvas *canvas) {
    canvas_ = canvas;
}

UIWindow::UIWindow(ContainLayer *layer)
    : is_mouse_in_(false),
    current_mouse_control_(NULL),
    root_control_(NULL),
    layer(layer) {

    }

UIWindow::~UIWindow() {
    delete root_control_;
}


void UIWindow::HandleMessage(Event &e) {
    if(e.where == kWmMouseEvent) {
        HandleMouseMessage(e);
    }else if(e.where == kWmKeyEvent){
        HandleKBMessage(e);
    }
}

void UIWindow::AddRootControl(UIControl *root_control) {
    if(root_control_) {
        delete root_control_;
    }
    root_control_ = root_control;
    root_control_->SetParentWin(this);
}

void UIWindow::Render(const Rect *rect) {
    if (root_control_) {
        root_control_->Render(rect);
    }
}

void UIWindow::UpdateLayout() {
    DoUpdateLayout();
    Rect rect(0, 0, layer->region.GetWidth() + 1, layer->region.GetHeight() + 1);
    Invalidate(&rect);
}

void UIWindow::RenderLayout() {
    DoUpdateLayout();
    UICanvas canvas(layer->region.GetWidth() + 1, layer->region.GetHeight() + 1, background_color);
    SetCanvas(&canvas);

    Rect rect(0, 0, layer->region.GetWidth(), layer->region.GetHeight() );
    Render(&rect);

    layer->RenderUIWindow(canvas.bitmap);
    SetCanvas(NULL);
}

void UIWindow::Invalidate(Rect* rect) {

    UICanvas canvas(layer->region.GetWidth() + 1, layer->region.GetHeight() + 1, background_color);
    SetCanvas(&canvas);

    Render(rect);
    layer->Redraw(rect, canvas.bitmap);

    SetCanvas(NULL);
}

void UIWindow::DoUpdateLayout() {
    if (root_control_) {
        Rect rect(0, 0, layer->region.GetWidth(), layer->region.GetHeight() );
        root_control_->SetRootFrame(&rect);
    }
}

void UIWindow::HandleKBMessage(Event e) {
    if(current_mouse_control_) {
        current_mouse_control_->OnKeyMessage(e);
    }
}

void UIWindow::HandleMouseMessage(Event e) {
    if (e.type == kWmMouseLeave) {
        SetCurrentMouseControl(NULL, e);
        is_mouse_in_ = false;
        return;
    }else if(e.type == kWmMouseEnter) {
        SetCurrentMouseControl(NULL, e);
        is_mouse_in_ = true;
        return;
    }

    if (root_control_) {
        Point point(e.x, e.y);
        UIControl *mouse_control = 
            root_control_->LookupMouseFocusedControl(point);
        if (e.type == kWmMouseMove) {
            SetCurrentMouseControl(mouse_control, e);
        }
        mouse_control->DispatchMouseMessage(e);
    }
}

void UIWindow::SetCurrentMouseControl(UIControl *control, Event e) {
    if (current_mouse_control_ == control) {
        return;
    }
    if (current_mouse_control_) {
        e.type = kWmMouseLeave;
        current_mouse_control_->DispatchMouseMessage(e);
    }
    if (control) {
        e.type = kWmMouseEnter;
        control->DispatchMouseMessage(e);
    }
    current_mouse_control_ = control;
}

    UIControl::UIControl()
:parent_(NULL),
    parent_win_(NULL),
    tag_(0),
    visible_(true),
    parent_visible_(true),
    alignment_type_(kAlignmentLeftTop)
{
}

UIControl::~UIControl() {
    for(size_t i = 0; i < children_.size(); ++i) {
        delete children_[i];
    }
}

UIWindow* UIControl::GetParentWin() {
    if (parent_win_ == NULL && parent_) {
        parent_win_ = parent_->GetParentWin();
    }
    return parent_win_;
}

Alignment  UIControl::GetAlignmentByString(const char *value) {
    Alignment alignment = kAlignmentLeftTop;

    static bool init_alignment_list = false;
    static std::vector<std::pair<const char *,Alignment> > alignments;

    if (!init_alignment_list) {
        alignments.push_back(std::make_pair("left_top",kAlignmentLeftTop));
        alignments.push_back(std::make_pair("left_center",kAlignmentLeftCenter));
        alignments.push_back(std::make_pair("left_bottom",kAlignmentLeftBottom));
        alignments.push_back(std::make_pair("center_top",kAlignmentCenterTop));
        alignments.push_back(std::make_pair("center",kAlignmentCenter));
        alignments.push_back(std::make_pair("center_bottom",kAlignmentCenterBottom));
        alignments.push_back(std::make_pair("right_top",kAlignmentRightTop));
        alignments.push_back(std::make_pair("right_center",kAlignmentRightCenter));
        alignments.push_back(std::make_pair("right_bottom",kAlignmentRightBottom));
        alignments.push_back(std::make_pair("left",kAlignmentLeft));
        alignments.push_back(std::make_pair("right",kAlignmentRight));
        alignments.push_back(std::make_pair("top",kAlignmentTop));
        alignments.push_back(std::make_pair("bottom",kAlignmentBottom));
        alignments.push_back(std::make_pair("fill",kAlignmentFill));
        init_alignment_list = true;
    }

    for (size_t i = 0; i < alignments.size(); ++i) {
        std::pair<const char *,Alignment> &pair = alignments[i];
        if(!strcmp(pair.first,value) ) {
            alignment = pair.second;
            break;
        }
    }
    return alignment;
}

void UIControl::SetAttribute(const char* name, const char *value) {

    if(!strcmp(name, "name") ) {
        SetControlName(value);

    }else if(!strcmp(name, "tag") ) {
        SetTag(atoi(value) );

    }else if(!strcmp(name, "size") ) {
        UISize size;
        sscanf(value, "%d,%d", &size.cx, &size.cy);
        SetSize(size);

    }else if(!strcmp(name, "margin") ) {
        UIMargin margin;
        sscanf(value, "%d,%d,%d,%d",
               &margin.left, &margin.top, &margin.right, &margin.bottom);
        SetMargin(margin);

    }else if(!strcmp(name, "alignment") ) {
        Alignment alignment = GetAlignmentByString(value);
        SetAlignment(alignment);

    }else if(!strcmp(name,"visible") ) {
        SetVisible(!strcmp(value,"true") );
    }
}

void UIControl::SetVisible(bool visible) {
    visible_ = visible;    
    for (size_t i = 0; i < children_.size(); ++i) {
        children_[i]->SetParentVisibleRecursive(visible);
    }
}

bool UIControl::IsVisible() const {
    return parent_visible_ && visible_;
}

void UIControl::SetControlName(const char *name) {
    name_ = name;
}

std::string UIControl::GetControlName() const {
    return name_;
}

void UIControl::SetTag(int tag) {
    tag_ = tag;
}

int UIControl::GetTag() const {
    return tag_;
}

void UIControl::SetMargin(const UIMargin &margin) {
    margin_ = margin;
    SetNeedLayout();
}

void UIControl::SetMargin(int left,int top /* = 0 */,int right /* = 0 */,int bottom /* = 0 */) {
    SetMargin( UIMargin(left,top,right,bottom) );
}

void UIControl::SetSize(const UISize &size) {
    size_ = size;
    SetNeedLayout();
}

void UIControl::SetSize(int width,int height) {
    SetSize(UISize(width,height));
}

UISize UIControl::GetSize() const {
    return size_;
}

void UIControl::SetAlignment(Alignment type) {
    alignment_type_ = type;
    SetNeedLayout();
}

Alignment UIControl::GetAlignment() const {
    return alignment_type_;
}

void UIControl::SetParent(UIControl *control) {
    assert(control != NULL);
    parent_ = control;
}

UIControl* UIControl::GetParent() const { 
    return parent_;
}

void UIControl::AddSubControl(UIControl *control) {
    assert(control != NULL);
    control->SetParent(this);
    children_.push_back(control);
}

void UIControl::RemoveSubControl(const std::string &name) {
    if (name.empty() ) {
        return;
    }
    for (std::vector<UIControl *>::iterator it = children_.begin();
         it != children_.end(); ++it) {
        if (!name.compare((*it)->GetControlName() ) ) {
            children_.erase(it);
            delete *it;
            break;
        }
    }
}

void UIControl::Render(const Rect *parent_rect) {
    Rect rect;
    bool res = Rect::IntersetRect(rect, frame_, *parent_rect);
    // printf("id : %d res : %s\n", tag_, res ? "true" : "false");
    // frame_.print();
    // parent_rect->print();
    // TrackLog();
    if(res) {
        RenderSelf(&rect);
        // TrackLog();
        for (size_t i = 0; i < children_.size(); ++i) {
            UIControl *child = children_[i];
            child->Render(&rect);
        }
    }
    // TrackLog();
}

void UIControl::RenderSelf(const Rect *rect) {

}

void UIControl::ArrangeSelf(const Rect *parent_frame) {
    int x = 0;
    int y = 0;
    int width  = size_.cx;
    int height = size_.cy;

    switch(alignment_type_) {
        //绝对定位
    case kAlignmentLeftTop:
        x = parent_frame->GetX() + margin_.left;;
        y = parent_frame->GetY() + margin_.top;
        break;
    case kAlignmentLeftCenter:
        x = parent_frame->GetX() + margin_.left;
        y = parent_frame->GetY() + ((parent_frame->GetHeight() - size_.cy) >> 1);
        break;
    case kAlignmentLeftBottom:
        x = parent_frame->GetX() + margin_.left;
        y = parent_frame->GetY() + parent_frame->GetHeight() - size_.cy - margin_.bottom;
        break;
    case kAlignmentCenterTop:
        x = parent_frame->GetX() + ((parent_frame->GetWidth() - size_.cx) >> 1) ;
        y = parent_frame->GetY() + margin_.top;
        break;
    case kAlignmentCenter:
        x = parent_frame->GetX() + ((parent_frame->GetWidth() - size_.cx) >> 1);
        y = parent_frame->GetY() + ((parent_frame->GetHeight() - size_.cy) >> 1);
        break;
    case kAlignmentCenterBottom:
        x = parent_frame->GetX() + ((parent_frame->GetWidth() - size_.cx) >> 1);
        y = parent_frame->GetY() + parent_frame->GetHeight() - size_.cy - margin_.bottom;
        break;
    case kAlignmentRightTop:
        x = parent_frame->GetX() +  parent_frame->GetWidth() - size_.cx - margin_.right;
        y = parent_frame->GetY() + margin_.top;
        break;
    case kAlignmentRightCenter:
        x = parent_frame->GetX() +  parent_frame->GetWidth() - size_.cx - margin_.right;
        y = parent_frame->GetY() + ((parent_frame->GetHeight() - size_.cy) >> 1);
        break;
    case kAlignmentRightBottom:
        x = parent_frame->GetX() +  parent_frame->GetWidth() - size_.cx - margin_.right;
        y = parent_frame->GetY() + parent_frame->GetHeight() - size_.cy - margin_.bottom;
        break;
        //相对定位
    case kAlignmentLeft:
        x       = parent_frame->GetX() + margin_.left;
        y       = parent_frame->GetY() + margin_.top;
        height  = parent_frame->GetHeight() - margin_.top - margin_.bottom;
        break;
    case kAlignmentRight:
        x       = parent_frame->GetX() + parent_frame->GetWidth() - size_.cx - margin_.right;
        y       = parent_frame->GetY() + margin_.top;
        height  = parent_frame->GetHeight() - margin_.top - margin_.bottom;
        break;
    case kAlignmentTop:
        x       = parent_frame->GetX() + margin_.left;
        y       = parent_frame->GetY() + margin_.top;
        width   = parent_frame->GetWidth() - margin_.left - margin_.right;
        break;
    case kAlignmentBottom:
        x       = parent_frame->GetX() + margin_.left;
        y       = parent_frame->GetY() + parent_frame->GetHeight() - size_.cy - margin_.bottom;
        width   = parent_frame->GetWidth() - margin_.left - margin_.right;
        break;
    case kAlignmentFill:
        x       = parent_frame->GetX() + margin_.left;
        y       = parent_frame->GetY() + margin_.top;
        width   = parent_frame->GetWidth() - margin_.left - margin_.right ;
        height  = parent_frame->GetHeight() - margin_.top - margin_.bottom;
        break;
    default:
        assert(0);
        break;
    }
    frame_ = Rect(x, y, x + width, y + height);
}

UIControl*  UIControl::LookupMouseFocusedControl(const Point &point) {
    UIControl *find_control = this;
    for (size_t i = children_.size(); i > 0; --i) {
        UIControl *control = children_[i - 1];
        if (control->IsVisible() && control->IsMouseInControl(point) ) {
            find_control = control->LookupMouseFocusedControl(point);
            break;
        }
    }
    return find_control;
}

void UIControl::SetRootFrame(const Rect *rect) {
    SetFrame(rect);
    ArrangeChildren(&frame_);
}

void UIControl::Arrange(const Rect * parent_frame){
    ArrangeSelf(parent_frame);
    ArrangeChildren(&frame_);
}

void UIControl::ArrangeChildren(const Rect *parent_frame) {
    for (size_t i = 0; i < children_.size(); ++i) {
        children_[i]->Arrange(parent_frame);
    }
}

void UIControl::SetParentWin(UIWindow *window) {
    assert(window != NULL);
    parent_win_ = window;
}

void UIControl::SetFrame(const Rect *rect) {
    frame_ = *rect;
}

Rect UIControl::GetFrame() const {
    return frame_; 
}

void UIControl::SetNeedLayout() {
    UIWindow *parent_win = GetParentWin();
    if (parent_win) {
        parent_win->UpdateLayout();//redraw all container
    }
}

void UIControl::SetNeedDisplay() {
    UIWindow *parent_win = GetParentWin();
    if (parent_win) {
        parent_win->Invalidate(&frame_);//redraw all container
    }
}

bool UIControl::OnMouseMessage(Event e) {
    bool message_handled = false;
    if(e.type == kWmMouseEnter) {
        OnMouseEntered(e);
        message_handled = true; 
    }else if(e.type ==  kWmMouseLeave) {
        OnMouseExited(e);
        message_handled = true;
    }else if(e.type == kWmMouseMove) {
        message_handled = OnMouseMove(e);
    }else if(e.type == kWmLeftButtonDown) {
        message_handled = OnLButtonDown(e);
    }else if(e.type == kWmLeftButtonUp) {
        message_handled = OnLButtonUp(e);
    }else if(e.type == kWmLeftButtonDClick) {
        message_handled = OnLButtonDoubleClicked(e);
    }
    return message_handled;
}

void UIControl::OnKeyMessage(Event e) {
    if(e.type == kWmKeyUp) {
        OnKeyUp(e);
    }else if(e.type == kWmKeyDown) {
        OnKeyDown(e);
    }
}

void UIControl::OnKeyDown(Event e) {

}

void UIControl::OnKeyUp(Event e) {

}

void UIControl::OnMouseEntered(Event e) {

}

void UIControl::OnMouseExited(Event e) {

}

bool UIControl::OnLButtonDown(Event e) {
    return false;
}

bool UIControl::OnLButtonUp(Event e) {
    return false;
}

bool UIControl::OnLButtonDoubleClicked(Event e) {
    return false;
}

bool UIControl::OnMouseMove(Event e) {
    return true;
}


void UIControl::SetParentVisibleRecursive(bool visible) {
    parent_visible_ = visible;
    for (size_t i = 0; i < children_.size(); i++) {
        children_[i]->SetParentVisibleRecursive(visible);
    }
}

bool UIControl::IsMouseInControl(const Point &point) {
    return frame_.PointInRect(point.x, point.y);
}

void UIControl::DispatchMouseMessage(Event e) {
    if (OnMouseMessage(e) == false) {
        UIControl *control = GetParent();
        if (control) {
            control->DispatchMouseMessage(e);
        }
    }
}

void UIControl::DispatchKeyMessage(Event e) {
    OnKeyMessage(e);
}

class UIDrawPanel : public UIControl, public UIObject {
public:
    void SetBitmap(Bitmap *bitmap);
    ~UIDrawPanel();
    UIDrawPanel();

    virtual bool OnLButtonDown(Event e);
    virtual bool OnLButtonUp(Event e);
public:
    virtual void RenderSelf(const Rect *rect);
private:
    Bitmap *bitmap;

public:
    Signal<Event> pressed;
    Signal<Event> released;

};

UIDrawPanel::UIDrawPanel(): bitmap(NULL) {

}

UIDrawPanel::~UIDrawPanel() {
    if(bitmap != NULL) {
        delete bitmap;
    }
}

bool UIDrawPanel::OnLButtonDown(Event e) {
    pressed(e);
    return true;
}

bool UIDrawPanel::OnLButtonUp(Event e) {
    released(e);
    return true;
}

void UIDrawPanel::SetBitmap(Bitmap *content) {
    if(bitmap != NULL) {
        delete bitmap;
    }
    bitmap = new Bitmap(content->width, content->height);
    bitmap->Bilt(0, 0, content, 0, 0, content->width, content->height);
    SetNeedDisplay();
}

void UIDrawPanel::RenderSelf(const Rect *rect) {
    if(bitmap) {
        UIWindow *parent_win = GetParentWin();
        // TrackLog();
        UICanvas *canvas = parent_win->GetCanvas();
        // TrackLog();
        canvas->DrawBitmap(bitmap, frame_);
    }
}

class UIPanel : public UIControl , public UIObject{
public:
    void SetBackgroundColor(Color color);
    void SetBackgroundImage(const std::string &filepath);

public:
    virtual void RenderSelf(const Rect *rect);

private:
    Color bk_color_;
    std::string bk_image_filepath_;
};

void UIPanel::SetBackgroundColor(Color color) {
    bk_color_ = color;
}

void UIPanel::SetBackgroundImage(const std::string &filepath) {
    bk_image_filepath_ = filepath;
}

void UIPanel::RenderSelf(const Rect *rect) {
    UIWindow *parent_win = GetParentWin();
    UICanvas *canvas = parent_win->GetCanvas();
    canvas->FillRect(frame_, bk_color_);

    if(!bk_image_filepath_.empty() ) {
        canvas->DrawImage(bk_image_filepath_, frame_, true);
    }
}

enum UIButtonStatus {
    kUIButtonStatusNormal,
    kUIButtonStatusHover,
    kUIButtonStatusPressed,
};


class UIButton : public UIControl , public UIObject{
public:
    struct Config {
        Config();
        std::string    button_text_;           
        std::string    normal_image_;          
        std::string    hover_image_;           
        std::string    pressed_image_;         
        Color         text_normal_color_;
        Color         text_focus_color_;
        Point         text_offset_;
        TextAlignment   text_alignment_;
    };

public:
    UIButton();

    void    SetText(const std::string text);
    void    SetNormalImage(const std::string filepath);
    void    SetHoverImage(const std::string filepath);
    void    SetPressedImage(const std::string filepath);
    void    SetTextColor(Color color);
    void    SetFocusTextColor(Color color);
    void    SetTextOffset(const Point &offset);
    void    SetTextAlignment(TextAlignment alignment);
    void    LoadConfig(const UIButton::Config &config);

public:
    virtual void    RenderSelf(const Rect *rect);

    virtual void    OnMouseEntered(Event e);
    virtual void    OnMouseExited(Event e);
    virtual bool    OnLButtonDown(Event e);
    virtual bool    OnLButtonUp(Event e);
private:
    void    SetButtonStatus(UIButtonStatus status);
    void    DrawText();
    void    OnClicked();
private:
    UIButtonStatus  button_status_;
    bool            self_clicked_;
    Config  config_;

public:
    Signal<long> clicked;
    Signal<long> pressed;
    Signal<long> released;
};

UIButton::Config::Config()
    :text_normal_color_(1, 1, 1),
    text_focus_color_(1, 1, 1),
    text_alignment_(kTextAlignmentCenter) {

    }

UIButton::UIButton()
    :button_status_(kUIButtonStatusNormal),
    self_clicked_(false) {

    }

void UIButton::SetText(const std::string text) {
    config_.button_text_ = text;
    SetNeedDisplay();
}

void    UIButton::SetNormalImage(const std::string filepath) {
    config_.normal_image_ = filepath;
}

void UIButton::SetHoverImage(const std::string filepath) {
    config_.hover_image_ = filepath;
}

void UIButton::SetPressedImage(const std::string filepath) {
    config_.pressed_image_ = filepath;
}

void UIButton::SetTextColor(Color color) {
    config_.text_normal_color_ = color;
}

void UIButton::SetFocusTextColor(Color color) {
    config_.text_focus_color_ = color;
}

void UIButton::SetTextOffset(const Point &offset) {
    config_.text_offset_ = offset;
}

void UIButton::SetTextAlignment(TextAlignment alignment)
{
    config_.text_alignment_ = alignment;
}

void UIButton::LoadConfig(const UIButton::Config &config) {
    config_ = config;
    SetNeedDisplay();
}

void UIButton::OnMouseEntered(Event e) {
    SetButtonStatus(kUIButtonStatusHover);
}

void UIButton::OnMouseExited(Event e) {
    SetButtonStatus(kUIButtonStatusNormal);
    self_clicked_ = false;
}

bool UIButton::OnLButtonDown(Event e) {
    SetButtonStatus(kUIButtonStatusPressed);
    self_clicked_ = true;
    return true;
}

bool UIButton::OnLButtonUp(Event e) {
    SetButtonStatus(kUIButtonStatusHover);
    if (self_clicked_) {
        OnClicked();
        self_clicked_ = false;
    }
    return true;
}

void UIButton::RenderSelf(const Rect *rect) {
    UIWindow *parent_win = GetParentWin();
    UICanvas *canvas = parent_win->GetCanvas();
    switch(button_status_) {
    case kUIButtonStatusNormal:
        if (!config_.normal_image_.empty() ){
            canvas->DrawImage(config_.normal_image_,frame_);
        }
        break;
    case kUIButtonStatusHover:
        if (!config_.hover_image_.empty() ) {
            canvas->DrawImage(config_.hover_image_,frame_);
        }
        break;
    case kUIButtonStatusPressed:
        if (!config_.pressed_image_.empty() ) {
            canvas->DrawImage(config_.pressed_image_,frame_);
        }
        break;
    default:
        break;
    }
    DrawText();
}

void UIButton::SetButtonStatus(UIButtonStatus status) {
    button_status_ = status;
    SetNeedDisplay();
}

void UIButton::DrawText() {
    if (!config_.button_text_.empty()) {
        Color color = config_.text_normal_color_;
        if (button_status_ == kUIButtonStatusHover || 
            button_status_ == kUIButtonStatusPressed) {
            color = config_.text_focus_color_;
        }
        Point &offset = config_.text_offset_;
        int width = frame_.GetWidth();
        int height= frame_.GetHeight();
        int x = frame_.GetX() + offset.x;
        int y = frame_.GetY() + offset.y;
        Rect text_rect(x, y, width + x,height + y);

        std::string &button_text = config_.button_text_;
        UIWindow *parent_win = GetParentWin();
        UICanvas *canvas = parent_win->GetCanvas();
        canvas->DrawText(button_text, text_rect, color, 16, kTextAlignmentCenter | kTextAlignmentVCenter);
    }
}

void UIButton::OnClicked() {
    clicked(0);
}


class UILabel : public UIControl, public UIObject {
public:
    struct  Config {
        Config();
        std::string    text_;
        Color         text_color_;
        TextAlignment   alignment_;
        int font_size_;
    };

public:
    UILabel();

    void  SetText(const std::string text);
    void  SetTextColor(Rgb color);
    void  LoadConfig(const UILabel::Config &config);
public:
    virtual void RenderSelf(const Rect *rect);

private:
    Config   config_;
};

UILabel::Config::Config()
    :text_color_(5, 5, 5),
    alignment_(kTextAlignmentVCenter),
    font_size_(14) {
    }

UILabel::UILabel() { }

void UILabel::SetText(const std::string text) {
    config_.text_ = text;
    SetNeedDisplay();
}

void UILabel::SetTextColor(Rgb color) {
    config_.text_color_ = Color::FromRGB(color);
}

void UILabel::LoadConfig(const UILabel::Config &config) {
    config_ = config;
    SetNeedDisplay();
}

void UILabel::RenderSelf(const Rect *rect) {
    UIWindow *parent_win = GetParentWin();
    UICanvas *canvas = parent_win->GetCanvas();
    canvas->DrawText(config_.text_, frame_, config_.text_color_, config_.font_size_);
}

class UIEdit : public UIControl {
public:
    struct Config {
        Config();
        Color         border_color_;
        Color         text_color_;
        bool           is_password_edit_;
        std::string    text_;
    };

public:
    UIEdit();

    const std::string GetEditText() const;
    void    SetEditText(const std::string text, bool redraw = false);

    void    SetBorderColor(Color color);
    void    SetTextColor(Color color);
    void    SetAsPasswordEdit(bool is_password_edit);
    void    LoadConfig(const UIEdit::Config &config);
public:
    virtual void    RenderSelf(const Rect *rect);

    virtual void    OnMouseEntered(Event e);
    virtual void    OnMouseExited(Event e);
    virtual bool    OnMouseMove(Event e);
    virtual bool    OnLButtonDown(Event e);
    virtual void OnKeyDown(Event e);
    virtual void OnKeyUp(Event e);

private:
    void OnDetectedTextChanged(char code);
private:
    UIEdit::Config    config_;
    bool text_changed;
public:
    Signal<char> TextChanged;
};

    UIEdit::Config::Config()
:border_color_(1, 1, 1),
    text_color_(1, 1, 1),
    is_password_edit_(false)
{

}

UIEdit::UIEdit() : text_changed(false) {

}

const std::string UIEdit::GetEditText() const {
    return config_.text_;
}

void UIEdit::SetEditText(const std::string text, bool redraw) {
    config_.text_ = text;
    if (redraw) {
        SetNeedDisplay();
    }
}

void UIEdit::SetBorderColor(Color color) {
    config_.border_color_ = color;
}

void UIEdit::SetTextColor(Color color) {
    config_.text_color_ = color;
}

void UIEdit::SetAsPasswordEdit(bool is_password_edit) {
    config_.is_password_edit_ = is_password_edit;
}

void UIEdit::LoadConfig(const UIEdit::Config &config) {
    config_ = config;
    SetNeedDisplay();
}

void  UIEdit::RenderSelf(const Rect *rect) {
    UIWindow *parent_win = GetParentWin();
    UICanvas *canvas = parent_win->GetCanvas();
    canvas->Rectangle(frame_,config_.border_color_);

    Rect text_rect = frame_;
    text_rect.Inflate(-3, 0);

    std::string text;
    std::string unicode_text;
    if (config_.is_password_edit_) {
        for (size_t i = 0; i < config_.text_.length(); ++i) {
            unicode_text += "*";
        }
        text = unicode_text;
    }
    else {
        text = config_.text_;
    }
    canvas->DrawText(text, text_rect, config_.text_color_, 14, kTextAlignmentVCenter | kTextAlignmentLeft);
}

void UIEdit::OnMouseEntered(Event e) {
}

void UIEdit::OnMouseExited(Event e) {
}

bool UIEdit::OnMouseMove(Event e) {
    return true;
}

bool UIEdit::OnLButtonDown(Event e) {
    return true;
}

void UIEdit::OnDetectedTextChanged(char code) {
	//printf("%d %d\n", code, code);
    if(code == 242) {//BACKSPACE
        config_.text_ = config_.text_.substr(0, config_.text_.length() - 1);
    }else {
        config_.text_.push_back(code);
    }
    SetNeedDisplay();
    TextChanged(code);
}

void UIEdit::OnKeyDown(Event e) {
    text_changed = true;
}

void UIEdit::OnKeyUp(Event e) {
    if(text_changed) {
        OnDetectedTextChanged(e.code);
        text_changed = false;
    }
}


//**************** !APP1 window ****************
UILabel::Config *GetDefaultLabelConfig() {
    static UILabel::Config *config = NULL;
    if (!config) {
        config = new UILabel::Config();
    }
    return config;
}

UIEdit::Config *GetDefaultEditConfig() {
    static UIEdit::Config *config = NULL;
    if (!config) {
        config = new UIEdit::Config();
    }
    return config;
}

UIButton::Config *GetDefaultButtonConfig() {
    static UIButton::Config *config = NULL;
    if (!config) {
        config = new UIButton::Config();
        config->text_normal_color_  = Color(1, 1, 1);
        config->text_focus_color_   = Color(1, 1, 1);
        config->normal_image_       =  "./resources/common_normal.png";
        config->hover_image_        = "./resources/common_hover.png";  
        config->pressed_image_      = "./resources/common_pressed.png";
    }
    return config;
}

class Demo1 {
public:
    Demo1(UILabel *label, UIEdit *username, UIEdit *password);
slot:
    void Login(long param);

private:
    UILabel *status_;
    UIEdit *username_;
    UIEdit *password_;
    int count_;
    bool lock;
};

Demo1::Demo1(UILabel *label, UIEdit *username, UIEdit *password) 
    : status_(label),
    username_(username),
    password_(password),
    count_(3),
    lock(false) {

    }

void Demo1::Login(long param) {
    if(!lock && status_ && username_ && password_) {
        std::string username = username_->GetEditText();
        std::string password = password_->GetEditText();

        if(username == "admin" && password == "123") {
            std::string text = "用户(" + username + ") 登录成功!";
            status_->SetText(text);
        }else {
            char text[64];
            --count_;
            if(count_ == 0) {
                status_->SetText("登录失败已３次，已锁死用户");
                lock = true;
                return;
            }
            sprintf(text, "登录失败! 还有 %d 次机会!", count_);
            status_->SetText(text);
        }
    }
}

AppWindow* CreateAppDemo1(WindowManager *wm) {

    UIControl *root_control = new UIControl();

    UIPanel *panel = new UIPanel();
    panel->SetSize(320, 160);
    panel->SetAlignment(kAlignmentCenterTop);
    panel->SetMargin(0, 20);
    panel->SetBackgroundColor(Color::FromRGB(GREEN));
    panel->SetBackgroundImage("./desktop.jpg");
    root_control->AddSubControl(panel);

    UILabel *label = new UILabel();
    label->SetSize(120, 20);
    label->LoadConfig(*GetDefaultLabelConfig() );
    label->SetAlignment(kAlignmentCenterTop);
    label->SetMargin(0, 200);
    label->SetText("用户名:");
    root_control->AddSubControl(label);

    UIEdit *user_edit = new UIEdit();
    user_edit->SetSize(120, 28);
    user_edit->LoadConfig(*GetDefaultEditConfig() );
    user_edit->SetAlignment(kAlignmentCenterTop);
    user_edit->SetMargin(0, 220);

    user_edit->SetEditText("");
    root_control->AddSubControl(user_edit);


    UILabel *label2 = new UILabel();
    label2->SetSize(120, 28);
    label2->LoadConfig(*GetDefaultLabelConfig() );
    label2->SetAlignment(kAlignmentCenterTop);
    label2->SetMargin(0, 260);
    label2->SetText("密码:");
    root_control->AddSubControl(label2);

    UIEdit *password = new UIEdit();
    password->SetSize(120, 28);
    password->LoadConfig(*GetDefaultEditConfig() );

    password->SetAlignment(kAlignmentCenterTop);
    password->SetMargin(0, 280);

    password->SetAsPasswordEdit(true);
    root_control->AddSubControl(password);

    UIButton *button = new UIButton();
    button->SetSize(100, 30);
    button->LoadConfig(*GetDefaultButtonConfig());

    button->SetAlignment(kAlignmentCenterTop);
    button->SetMargin(0, 330);
    button->SetText("登录");
    root_control->AddSubControl(button);

    UILabel *status = new UILabel();
    status->SetSize(190, 28);
    status->LoadConfig(*GetDefaultLabelConfig() );
    status->SetAlignment(kAlignmentCenterTop);
    status->SetMargin(0, 370);
    status->SetTextColor(RED);
    status->SetText("");
    root_control->AddSubControl(status);

    Demo1 *demo = new Demo1(status, user_edit, password);
    UIObject::Connect(button, &UIButton::clicked, demo, &Demo1::Login);
    return wm->CreateWindow("Window Top", 400, 400, 10, 10, WHITE, root_control); 
}


//**************App2***************
class RenderEngine {
public:
    virtual void RenderCard(int card[4][4], int w, int h) = 0;
    virtual void RenderGameOver(int score) = 0;
    virtual void RenderScore(int score) = 0;
    virtual ~RenderEngine() {}
};

class Game2048 {
public:
    enum Direction {
        kLeft,
        kRight,
        kUp,
        kDown
    };
private:
    typedef struct {
        char direction;
        bool (Game2048::*handler)();
    }Operator;

public:
    Game2048(RenderEngine *engine);
    ~Game2048();
    void Init();
    void Operate(Direction direction);
private:
    bool DoLeft();
    void DoCreateCardNumber();
    bool DoCheckGameOver();
    bool DoRight();
    bool DoUp();
    bool DoDown();
    bool SetCardV(int &x, int &y, int &x1, Direction direction);
    bool SetCardH(int &x, int &y, int &y1, Direction direction);
    void RenderCard();
    int Random(int a, int b);
private:
    int card[4][4];
    int score;
    RenderEngine *render_engine;
    bool gameover;
};

class DrawPanelEngine : public RenderEngine {
public:
    void RenderCard(int card[4][4], int w, int h);
    void RenderGameOver(int score);
    void RenderScore(int score);

    DrawPanelEngine(UIDrawPanel *panel, UILabel *label);
    ~DrawPanelEngine();
private:
    UIDrawPanel *panel_;
    UILabel *score_;
    std::map<int, Bitmap* > card_bitmap;
};

DrawPanelEngine::DrawPanelEngine(UIDrawPanel *panel, UILabel *label) :
    panel_(panel), score_(label) {
        char buf[32];
        FontManager &font = FontManager::GetInstance();

        for(int number = 0; number <= 2048; number = number * 2) {
            Bitmap *card = new Bitmap(64, 64);

            if (number == 0) {
                Color color(200, 190, 180);
                card->FillColor(color.ToRGB() );
                card_bitmap[number] = card;

                number = 1;
                continue;

            }else if (number == 2) {  
                Color color(240, 230, 220);
                card->FillColor(color.ToRGB() );
            }else if (number == 4) {  
                Color color(240, 220, 200);  
                card->FillColor(color.ToRGB() );
            }else if (number == 8) {  
                Color color(240, 180, 120);
                card->FillColor(color.ToRGB() );
            }else if (number == 16) {  
                Color color(240, 140, 90);  
                card->FillColor(color.ToRGB() );

            }else if (number == 32) {  
                Color color(240, 120, 90); 
                card->FillColor(color.ToRGB() ); 

            }else if (number == 64) {  
                Color color(240, 90, 60); 
                card->FillColor(color.ToRGB() ); 

            }else if (number == 128) {  
                Color color(240, 90, 60);  
                card->FillColor(color.ToRGB() );

            }else if (number == 256) {  
                Color color(240, 200, 70); 
                card->FillColor(color.ToRGB() ); 

            }else if (number == 512) {  
                Color color(240, 200, 70);  
                card->FillColor(color.ToRGB() );

            }else if (number == 1024) {  
                Color color(0, 130, 0);  
                card->FillColor(color.ToRGB() );

            }else if (number == 2048) {  
                Color color(0, 130, 0);  
                card->FillColor(color.ToRGB() );
            }

            sprintf(buf, "%d", number);
            Bitmap* text = font.DrawText(buf, 36, WHITE);
            card->BiltFont(card->width / 2 - text->width / 2, card->height / 2 - text->height / 2, 
                           text, 0, 0, text->width, text->height);

            card_bitmap[number] = card;
            delete text;
        }
    }

DrawPanelEngine::~DrawPanelEngine() {
    typedef std::map<int, Bitmap* > CardMap;

    for(CardMap::iterator iter = card_bitmap.begin(); 
        iter != card_bitmap.end(); ++iter) {
        delete iter->second;
    }
}

void DrawPanelEngine::RenderCard(int card[4][4], int w, int h) {
    Bitmap *background = new Bitmap(276, 276);
    Color color(180, 170, 160);
    background->FillColor(color.ToRGB() );
    // TrackLog();
    for(int y = 0; y < h; ++y) {
        int y_pos = 4 * (y + 1) + 64 * y;

        for(int x = 0; x < w; ++x) {
            int x_pos = 4 * (x + 1) + 64 * x;
            Bitmap* bitmap = card_bitmap[ card[x][y] ];

            background->Bilt(x_pos, y_pos, bitmap, 0, 0, bitmap->width, bitmap->height);
        }
    }
    panel_->SetBitmap(background);
    delete background;
}

void DrawPanelEngine::RenderScore(int score) {
    char buf[64] = "\0";
    sprintf(buf, "Score : %d", score);
    score_->SetText(buf);
}

void DrawPanelEngine::RenderGameOver(int score) {
    char buf[64] = "\0";
    sprintf(buf, "Game Over! Final Score : %d", score);
    score_->SetText(buf);
}


class Demo2 {
public:
    Demo2(UIDrawPanel *panel, UILabel *label);
    ~Demo2();    

private:
    int start_x;
    int start_y;
    Game2048 *game;
slot:
    void OnDragBegan(Event e);
    void OnDragEnd(Event e);
    void Run(long param);
};

void Demo2::Run(long param) {
    game->Init();
}

void Demo2::OnDragBegan(Event e) {
    start_x = e.x;
    start_y = e.y;
}

void Demo2::OnDragEnd(Event e) {
    int dst_x = start_x - e.x;  
    int dst_y = start_y - e.y;
    if(abs(dst_x) < 10 && abs(dst_y) < 10) {
        return;
    }

    if (abs(dst_x) > abs(dst_y)){  
        if (dst_x + 5 > 0) {  
            game->Operate(Game2048::kLeft);          
        } else {  
            game->Operate(Game2048::kRight);
        }  

    } else {  
        if (dst_y + 5 > 0) {  
            game->Operate(Game2048::kUp);
        } else {  
            game->Operate(Game2048::kDown);
        }
    }
}

Demo2::~Demo2() {
    delete game;
}

Demo2::Demo2(UIDrawPanel *panel, UILabel *label) : start_x(0), start_y(0) {
    RenderEngine *engine = new DrawPanelEngine(panel, label);
    game = new Game2048(engine);
}

int Game2048::Random(int a, int b) {
    static bool init = false;
    if(!init) {
        srand(unsigned(time(0) ) );
        init = true;
    }
    return rand() % (b - a + 1) + a;
}

Game2048::Game2048(RenderEngine *engine) : render_engine(engine), score(0) , gameover(false) {

}
Game2048::~Game2048() {
    delete render_engine;
}

void Game2048::RenderCard() {
    render_engine->RenderScore(score);
    // TrackLog();
    render_engine->RenderCard(card, 4, 4);
    // TrackLog();
}

void Game2048::Init() {
    for(int y = 0; y < 4; ++y) {
        for(int x = 0; x < 4; ++x) {
            card[x][y] = 0;
        }
    }
    score = 0;
    gameover = false;
    DoCreateCardNumber();
    DoCreateCardNumber();
    RenderCard();
}

void Game2048::Operate(Direction direction) {
    static Operator operators[] = {
        {kUp, &Game2048::DoUp},
        {kDown, &Game2048::DoDown},
        {kLeft, &Game2048::DoLeft},
        {kRight, &Game2048::DoRight}
    };
    static int len = sizeof(operators) / sizeof(Operator);

    if(gameover) {
        return;
    }

    for(int i = 0; i < len ; ++i) {
        if(operators[i].direction == direction) {
            bool res = (this->*operators[i].handler)();
            DoCreateCardNumber();
            RenderCard();
            if(res) {
                if(DoCheckGameOver() ) {
                    render_engine->RenderGameOver(score);
                    gameover = true;
                    return;
                }
            }
            break;
        } 
    }
}


void Game2048::DoCreateCardNumber() {

    int num = 0;
    for(int y = 0; y < 4; ++y) {
        for(int x = 0; x < 4; ++x) {
            if(card[x][y] != 0) {
                ++num;
            }
        }
    }
    if(num ==16) {
        return;
    }

    while(1) {
        int i = Random(1, 4) - 1;
        int j = Random(1, 4) - 1;

        if(card[i][j] == 0) {
            card[i][j] = Random(1, 10) == 10 ? 4 : 2;
            break;
        }
    }
}

bool Game2048::DoCheckGameOver() {
    bool isover = true;
    for(int y = 0; y < 4; ++y) {
        for(int x = 0; x < 4; ++x) {

            if(card[x][y] == 0 ||
               ( x > 0 && card[x][y] == card[x-1][y]) ||
               ( x < 3 && card[x][y] == card[x+1][y]) ||
               ( y > 0 && card[x][y] == card[x][y-1]) ||
               ( y < 3 && card[x][y] == card[x][y+1]) ) {

                isover = false;
            }
        }
    }

    return isover;
}

bool Game2048::SetCardH(int &x, int &y, int &x1, Direction direction) {
    bool isdo = false;
    if(card[x][y] == 0) {
        card[x][y] = card[x1][y];
        card[x1][y] = 0;
        if(direction == kLeft) {
            --x;
        }else {
            ++x;
        }
        isdo = true;
    } else if(card[x][y] == card[x1][y]) {
        card[x][y] = card[x][y] * 2;
        card[x1][y] = 0;

        score += card[x][y];
        isdo = true;
    }
    return isdo;
}

bool Game2048::SetCardV(int &x, int &y, int &y1, Direction direction) {
    bool isdo = false;
    if(card[x][y] == 0) {
        card[x][y] = card[x][y1];
        card[x][y1] = 0;
        if(direction == kUp) {
            ++y;
        }else {
            --y;
        }
        isdo = true;

    }else if(card[x][y] == card[x][y1]) {
        card[x][y] = card[x][y] * 2;
        card[x][y1] = 0;

        score += card[x][y];
        isdo = true;

    }
    return isdo;
}

bool Game2048::DoLeft() {
    bool isdo = false;
    for(int y = 0; y < 4; ++y) {
        for(int x = 0; x < 4; ++x) {

            for(int x1 = x + 1; x1 < 4; ++x1) {

                if(card[x1][y] > 0) {
                    isdo = SetCardH(x, y, x1, kLeft);
                    break;
                }
            }
        }
    }
    return isdo;
}

bool Game2048::DoRight() {
    bool isdo = false;

    for(int y = 0; y < 4; ++y) {
        for(int x = 3; x >= 0; --x) {

            for(int x1 = x - 1; x1 >= 0; --x1) {

                if(card[x1][y] > 0) {
                    isdo = SetCardH(x, y, x1, kRight);
                    break;
                }

            }
        }
    }
    return isdo;
}

bool Game2048::DoDown() {
    bool isdo = false;
    for(int x = 0; x < 4; ++x) {
        for(int y = 3; y >= 0; --y) {

            for(int y1 = y - 1; y1 >= 0; --y1) {

                if(card[x][y1] > 0) {
                    isdo = SetCardV(x, y, y1, kDown);
                    break;
                }
            }
        }
    }
    return isdo;
}

bool Game2048::DoUp() {
    bool isdo = false;
    for(int x = 0; x < 4; ++x) {
        for(int y = 0; y < 4; ++y) {

            for(int y1 = y + 1; y1 < 4; ++y1) {

                if(card[x][y1] > 0) {
                    isdo = SetCardV(x, y, y1, kUp);
                    break;
                }
            }
        }
    }
    return isdo;
}

AppWindow* CreateAppGame2048(WindowManager *wm) {

    UIControl *root_control = new UIControl();

    UILabel *label = new UILabel();
    label->SetSize(100, 20);
    UILabel::Config *config = GetDefaultLabelConfig();
    config->font_size_ = 16;
    label->LoadConfig(*config);
    label->SetAlignment(kAlignmentCenterTop);
    label->SetMargin(0, 20);
    label->SetText("2048");
    root_control->AddSubControl(label);


    UIButton *button = new UIButton();
    button->SetSize(100, 30);
    button->LoadConfig(*GetDefaultButtonConfig());

    button->SetAlignment(kAlignmentCenterTop);
    button->SetMargin(0, 45);
    button->SetText("开始游戏");
    root_control->AddSubControl(button);

    UIDrawPanel *panel = new UIDrawPanel();
    panel->SetSize(280, 280);
    panel->SetAlignment(kAlignmentCenterTop);
    panel->SetMargin(0, 90);
    root_control->AddSubControl(panel);

    Demo2 *demo2 = new Demo2(panel, label);

    UIObject::Connect(button, &UIButton::clicked, demo2, &Demo2::Run);
    UIObject::Connect(panel, &UIDrawPanel::pressed, demo2, &Demo2::OnDragBegan);
    UIObject::Connect(panel, &UIDrawPanel::released, demo2, &Demo2::OnDragEnd);

    return wm->CreateWindow("2048 Game", 360, 420, 20, 20, WHITE, root_control); 
}

//**************** !Main ****************
int main(int argc, char **argv)
{     
    WindowManager *wm = new WindowManager(kDefualtWmConfigFile);

    wm->AddIcon("Computer");
    wm->AddIcon("NetWork");
    wm->AddIcon("2048");
    wm->AddIcon("FireBird");

    // AppWindow *app2 = wm->CreateWindow("Window Top", 640, 480, 150, 150, WHITE);
    AppWindow *app2 = CreateAppDemo1(wm);
    // app2->set_alpha(30);
    // wm->PositionWindow(app2, kWinAlwayOnTop);
    wm->ShowWindow(app2);

    AppWindow *game2048 = CreateAppGame2048(wm);
    wm->ShowWindow(game2048);

    AppWindow *app1 = wm->CreateWindow("Window Normal1", 340, 240, 50, 50, WHITE, NULL);
    wm->ShowWindow(app1);


    AppWindow *app3 = wm->CreateWindow("Window Bottom", 240, 160, 100, 100, WHITE, NULL);
    app3->set_alpha(60);
    // wm->PositionWindow(app3, kWinAlwayOnBottom);
    wm->ShowWindow(app3);

    Window *app4 = wm->CreateWindow("Window Normal2", 320, 160, 0, 0, WHITE, NULL);
    wm->ShowWindow(app4);

    wm->Run();

    delete wm;
}
